اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
دو دقیقه
امروز حین کدنویسی به یک مشکل نادر برخورد کردم. کلاسی پایه داشتم (مثلا Person) که یک سری کلاس دیگر از آن ارث بری میکردند (مثلا کلاسهای Student و Teacher).در اینجا در کلاس پایه بصورت اتوماتیک یک ویژگی(Property) را روی کلاسهای مشتق شده مقدار دهی میکردم؛ مثلا به این شکل:
سپس در یک متد مجموعهای از Studentها و teacherها را ایجاد کرده و به لیستی از Personها اضافه میکنم:
اما در نهایت اتفاقی که رخ میداد این بود که PersonId همه Studentها یکسان میشد ولی قضیه به همین جا ختم نشد؛ وقتی خط به خط برنامه را Debug و مقادیر را Watch میکردم، مشاهده میکردم که PersonId به درستی ایجاد میشود.
در این حالت نیز دستورات درست عمل میکردند و personId متفاوتی ایجاد میشد!
public class Person { public Person() { personId= this.GetType().Name + (new Random()).Next(1, int.MaxValue); } }
var student1=new Student(){Name="Iraj",Age=21}; var student1=new Student(){Name="Nima",Age=20}; var student1=new Student(){Name="Sara",Age=25}; var student1=new Student(){Name="Mina",Age=22}; var student1=new Student(){Name="Narges",Age=26}; var teacher1=new Student(){Name="Navaei",Age=45}; var teacher2=new Student(){Name="Imani",Age=50};
در فیزیک نوین اصلی هست به نام عدم قطعیت هایزنبرگ که به زبان ساده میتوان گفت نحوه رخداد یک اتفاق، با توجه به وجود یا عدم وجود یک مشاهدهگر خارجی نتیجهی متفاوتی خواهد داشت.
کم کم داشتم به وجود قانون مشاهدهگر در برنامه نویسی هم ایمان پیدا میکردم که این کد فقط در صورتیکه آنرا مرحله به مرحله بررسی کنم جواب خواهد داد!
جالب اینکه زمانیکه personId را نیز ایجاد میکردم، یک دستور برای دیدن خروجی نوشتم مثل این
public class Person { public Person() { personId= this.GetType().Name + (new Random()).Next(1, int.MaxValue); Debug.Print(personId) } }
قبل از خواندن ادامه مطلب شما هم کمی فکر کنید که مشکل کجاست؟
این مشکل ربطی به قانون مشاهدهگر و یا دیگر قوانین فیزیکی نداشت. بلکه بدلیل سرعت بالای ایجاد وهله ها(instance) از کلاسیهای مطروحه (مثلا در زمانی کمتر از یک میلی ثانیه) زمانی در بازه یک کلاک CPU رخ میداد.
هر نوع ایجاد کندی (همچون نمایش مقادیر در خروجی) باعث میشود کلاک پردازنده نیز تغییر کند و عدد اتفاقی تولید شده فرق کند.
همچنین برای حل این مشکل میتوان از کلاس تولید کننده اعداد اتفاقی، شبیه زیر استفاده کرد:
using System; using System.Threading; public static class RandomProvider { private static int seed = Environment.TickCount; private static ThreadLocal<Random> randomWrapper = new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref seed)) ); public static Random GetThreadRandom() { return randomWrapper.Value; } }