چرا سازنده های پایتون از GIL استفاده کردند. و باعث شدن اجازه اجرای موازی thread ها را نداشته باشیم؟
1 پاسخ
به خاطر پیچیدگی مدیریت حافظه.
وقتی دو تا thread به صورت موازی اجرا بشوند سرعت اجرا دو برابر میشه ولی بهاش اینه که هماهنگ کردن بین thread ها سخت و پیچیده میشه. و thread ها تو حالت موازی باید با هم هماهنگ باشند وگرنه مشکل ساز میشه.
مشکل دوم اینه که حافظه thread ها در حالت موازی به اشتراک گذاشته میشه. یعنی حافظه آن ها مشترک است.
فرض کنید یک پروسه با آیدی 2400 داریم این پروسه یک حافظه و دو تا thread دارد .حافظه این پروسه بین دو thread مشترک است.
دو تا thread میتوانند به حافظه همدیگر دسترسی داشته باشند . البته به جز حافظه local توابع یا همان stack.
شما هر متغیری که در حافظه برنامه اتون تعریف میکنید بین تمام thread های برنامتون میتونه استفاده بشه و بهش دسترسی پیدا کنید به غیر از چیزایی که داخل scope توابع تعریف میکنید (مانند متغیر b در شکل)
مثلا اگر در thread1 تابعی به اسم name تعریف کردید و درون تابع یک متغیر به نام b تعریف کنید متغیر b فقط در thread1 و فقط درون تابع name قابل دسترسی است.
ولی اگر متغیر a را در thread1 بیرون از تابع تعریف کنید متغیر a در thread2 هم قابل دسترسی است. چون حافظه بین دو thread مشترک است.
حالا مشکل پیچیدگی در حالت موازی کجاست؟
فرض کنید در پروسه یا برنامه امون متغیر a=10 را خارج از توابع تعریف کردیم. پروسمون دو تا thread داره. الان هر دو thread به a=10 دسترسی دارند.
مثلا thread1 برنامه ریزی کرده که به متغیر a پنج تا اضافه کنه و thread2 برنامه ریزی کرده که متغیر a را برابر ۱۰۰ قرار بده.
اگر بذاریم دو تا thread به صورت موازی اجرا بشه. ترتیب اجرا threadها میتونه نتیجه a را متفاوت کند.
اگر اول thread1 اجرا بشه بعد thread2 :
Thread1 : a = 10 + 5 = 15
Thread2: a = 100
Result : a = 100
اگر اول thread2 اجرا بشه بعد thread1:
Thread2 : a = 100
Thread1 : a = 100 + 5 = 105
Result : a = 105
خب الان واقعا مقدار متغیر a چند؟
تو حالت عادی نمیتونیم مطمئن باشیم کدوم thread اول اجرا میشه. فرض کنید دو تا core داریم. Thread1 را روی core1 اجرا میکنیم و thread2 را روی core2 اجرا میکنیم. بستگی داره کدوم یکی از core ها سریعتر باشن و زودتر به متغیر a برسند و متغیر a را تغییر بدن. یا بستگی داره متغیر a تو کدوم فایل ها مقدارش زودتر تغییر کنه.
پس باید یه جوری دو برنامه از دو thread با هم هماهنگ و sync بشه. مثلا اگر میخواهید متغیر a اول تو thread2 مقدار بگیرد باید یه مکانیزم هماهنگ سازی داشته باشی که thread1 تا وقتی که thread2 متغیر a را عوض نکرده تغییری روی متغیر a اعمال نکنه.
پس نتیجه میگیریم اگر threadها موازی اجرا بشوند باید یه سری مکانیزم برای هماهنگ سازی بینشون وجود داشته باشه. حالا پایتون برای ساده سازی مدیریت حافظه گفته اصلا اجازه نمیدیم دو تا thread به صورت موازی اجرا بشوند.
اجرای threadها به صورت همروندی هم نیاز به هماهنگی دارد ولی کمتر از حالتی که به صورت موازی است.
سوالی که ممکن هست پیش بیاد اینه که پایتون تو حالت multithreading و برنامه نویسی همروندی چجوری تعیین میکنه از هر thread چقدر را انجام بده و دوباره سوییچ کنه؟
این مبحث خیلی گسترده است. اما به صورت خلاصه بگیم. به خاطر فعالیت های ورودی و خروجی ممکنه یه وقتایی بعضی از thread ها بیکار بشوند.
فرض کنید thread1 وظیفه داره از کاربر input بگیره. خب الان thread1 منتظر میمونه تا کاربر چیزی را وارد کنه. و برنامه عملا در زمانی که کاربر داره چیزی را وارد میکنه کاری انجام نمیده. خب پایتون به جای اینکه منتظر بمونه تا کاربر اطلاعاتش را وارد کنه میتونه سوییچ کنه رو thread2 و مقداری از کارش را انجام بده.
پس بر اساس زمان انتظار فعالیت های ورودی و خروجی ها میتونه تصمیم بگیره بین threadها سوییچ کنه.
اگر threadها همشون کارشون پردازشی باشه و فعالیت ورودی خروجی نداشته باشند چی؟ بعد از انجام دادن یه تعداد استاندارد کار که thread1 انجام داد پایتون خودش میاد سوییچ میکنه به thread2.
اطلاعات کاملتر در این لینک