
تعریف مسئله
فرض کنیم شما در حال نوشتن یک سرور هستید که کاربران زیادی به آن متصل میشوند و هر کاربر عملیاتی در سیسیتم تعریف میکند و نیاز است هر عملیات یک شناسه یکتا برای شناسایی داشته باشد.
در ساخت شناسه یکتا چندی فاکتور اصلی وجود دارد
- عوامل یکتا کننده یک ترد
- عوامل یکتا کننده چندین ترد
- عوامل یکتا کننده چندین پروسس
- عوامل یکتا کننده یک سیستم
عوامل یکتا کننده یک ترد
برای یکتایی شناسه در یک ترد میتونیم راحت یک شمارنده تعریف کنیم و اون رو اضافه کنیم و چون فقط با یک ترد با اون کار میکنیم همیشه یکتا خواهد بود.
عوامل یکتا کننده چندین ترد
اما اگر در یک پروسه چندین ترد داشته باشیم روش بالا با چالشهایی روبرو میگردد چون اگر هر ترد عدد خود را تولید کند در واقع هر عدد به اندازه تردها تکرار میشود. برای گریز از این موضوع میتواند به استفاده از اعداد تصادفی روی آورد که اوضاع را بهتر میکند و برای این که تضمین کرد مقدار یکتاست میتوان بعد از ساختن عدد آن را با اعداد موجود چک کرد و در صورت یکتا نبودن عدد جدیدی تولید نمود که این کار به دلیل بررسی اضافه هزینهبر است. اما روش اختصاص محدوده اعداد به تردهاست بدین صورت که برای مثال اگر قرار است محدوده اعداد تولید شده بین 0 تا 1000 باشد و ما 10 ترد داشته باشیم میتوانیم برای هر ترد محدوده تعیین کنیم بدین صورت که اعداد 0 تا 99 برای ترد اول و اعداد 100 تا 199 برای ترد دوم و به همین صورت اما مشکل اصلی این روش این است که لزوما همه تردها به یک اندازه کار نمیکنند و به یک اندازه عدد نیاز ندارند. برای حل این مشکل میتوان روند داینامیکی برای رزرو محدوده هر ترد است در این صورت مشکل اعداد اضافی برای یک ترد و کم آوردن اعداد در دیگر تردها پیش نمیآید و اعداد به روش بهتری تقسیم میشوند.
راه دیگر افزودن یک شناسه یکتا برای هر ترد است به این صورت که باید ظرف آیدی شما فضا برای افزودن عدد دیگری بجز عدد شناسه داشته باشد یعنی مثلا اگر شناسه شما از جنس اعداد صحیح 32 بیتی است باید از متغیری با فضای بزرگتری استفاده کنید تا بتوانید یک شناسه برای هر ترد به آن بیفزایید در این صورت شناسه هر ترد یکتا خواهد بود. اما مشکل این روش این است که یک اطلاعات اضافی به ازای نگه داشتن شناسه یکتای هر ترد در نظر گرفتهایم و استفاده از ظرف بزرگنیز مشکلاتی دارد از جمله این که متغیرهای معمولی دارای گنجایشهای مشخصی هستند برای مثال ظرف بزرگ تر از عدد صحیح 32 بیتی، عدد صحیح 64 بیتی میشود یعنی برای افزودن یک آیدی کوچک مجبور به دو برابر کردن حجم آیدی هستیم که مشکلات بعدی را به همراه دارد از طرفی اگر خودمان سایز متغیر را تغییر دهیم برای مثال آن را 40 بیتی کنیم نیز فضا بندی حافظه به روش استانداردی صورت نمیپذیرد و باز بهینه سازی کلاسهای عمومی روی آن سایز متغیر جواب نمیدهد و ...
روش دیگر استفاده از متغیرهای اتمی و افزایش آنهاست که این قابلیت را به ما میدهند که به صورت امن همزمان با چند ترد به آنها دسترسی پیدا کنیم و کار خود را انجام دهیم اما برای دقیق تر مشخص شدن این موضوع باید این روشها از نظر بازده با یکدیگر مقایسه شوند.
نکته: تمامی این تستها بر روی لپتاپ شخصی بنده با cpu intle 4710HQ گرفته شده است.
روش اول: استفاده از متغیر اتمیک به عنوان شمارنده
کد:
نتیجه:
536870910 done 536870910 done 536870910 done 536870910 done 536870910 done 536870910 done 536870910 done 536870910 done time of all threads 115.614 s Hello World!
همانطور که در مثال بالا دیدید برای تولید تمام اعداد در رنج 32 بیت با روش استفاده از شمارنده اتمیک حدود 115 ثانیه زمان نیاز داریم.
روش دوم: استفاده از محدوده ثابت
کد:
نتیجه:
536870910 done 536870910 done 536870910 done 536870910 done 536870910 done 536870910 done 536870910 done 536870910 done time of all threads 2.16762 s Hello World!
در این روش نسبت به روش قبل بهبود 53 برابری پرفورمنس را مشاهده میکنیم.
روش سوم : استفاده از محدوده پویا
نکته: بازده این روش بستگی به مقدار رزرو در هر بار دارد به این معنی که اگر این مقدار کم در نظر گرفته شود زمان بیشتری نیاز است و اگر بیشتر در نظر گرفته شود در زمان کمتری قادر به تولید تمام شناسهها هستیم اگر مقدار رزرو در هر بار را 30 هزار در نظر بگیریم تقریبا پرفورمنس مشابه مورد محدوده ثابت میشود.
کد:
نتیجه با رزرو 30 هزار عدد در هر بار:
682980000 done 437280000 done 460680000 done 572670000 done 551400000 done 563970000 done 321150000 done 704820000 done time of all threads 1.77828 s Hello World!
نتیجه با رزرو 300 هزار عدد در هر بار:
621300000 done 478200000 done 642900000 done 786000000 done 640200000 done 321300000 done 308100000 done 496800000 done time of all threads 1.89099 s Hello World!
عوامل یکتا کننده چندین پروسه
برای یکتایی چندین پروسه در یک سیستم نمیتوان فقط به شمارنده اکتفا کرد چون وقتی چندین پروسس داریم اگر بدون ارتباط با یکدیگر به تولید اعداد بپردازند احتمال تولید اعداد تکراری بسیار است.
برای این منظور باید به یک لایه بالاتر مراجعه کرد یعنی یا باید بخش مدیریت کننده ای برای این چند پروسس داشته باشیم یا از سیستم عامل کمک بگیریم.
برای یکتا سازی شناسه در چندین پروسس میتوانیم با افزودن شناسه خود پروسس به شناسه تولید شده در پروسس یک شناسه یکتا در کل سیستم بسازیم برای این منظور میتوانیم از سیستم عامل شناسه پروسه را گرفته و آن را به شناسه تولیدی یکتا در همان پروسه ادغام کرد.
عوامل یکتا کننده یک سیستم
برای یکتا سازی یک سیستم میتوان از آدرس Mac سیستم استفاده کرد که برای هر سیستم یکتاست. و باز باید از روش ادغام با آیدی یکتای پروسه استفاده کرد.
نتیجه:
برای ساخت یک شناسه یکتا نیاز است عوامل موجود در تولید ان را به خوبی شناسایی کنیم. یکی از روشهای عمومی برای تولید شناسه یکتا روش شناسه منحصربهفرد جهانی (UUID) است که با توجه به ساختار آن احتمال تکراری بودن شناسه تولید شده توسط آن بسیار پایین است. اما شما باید عوامل تاثیر گذار در شناسه خود را شناسایی کنید چون ممکن است حجم یا پردازشی بیشتری نسبت به نیاز واقعی خود مصرف کنید. برای مثال اگر شما در یک ترد مشغول به کار هستید افزودن آدرس MAC به شناسه تولید شده فقط حجم و پردازش بیشتری را میطلبد. بنابراین برای تولید شناسه یکتا اول عوامل تاثیر گذار خود را مشخص کنید و سپس به تولید آن اقدام کنید.