همزمانی و موازی سازی در پایتون

بله، من انتشار را در اینجا متوقف کرده بودم، اما از نظر بازاریابی بهتر است به انتشار ادامه دهید… ادامه دادیم.
متن اصلی در اینجا منتشر شده است.
هدف این متن ارائه خلاصه ای مستقیم از این است مفاهیم اساسی لازم برای درک همزمانی و موازی بودن در زبان پایتون. توصیه می کنم حداقل پیشینه در مورد موضوع داشته باشید یا این متن را با مطالعه از منابع دیگر ترکیب کنید. همه مراجع در انتهای متن آمده است.
موضوعات زیر را پوشش خواهم داد:
فرآیند چیست؟
در محاسبات الف فرآیند نمونه ای از یک برنامه در حال اجرا است. اگر برنامه ای مانند مرورگر را در رایانه خود باز کنید، آن برنامه با فرآیندی مرتبط می شود. یک فرآیند از موارد زیر تشکیل شده است:
- زمینه سخت افزاری: محتویات رجیسترهای عمومی و اختصاصی CPU را ذخیره می کند
- زمینه نرم افزار: منابع قابل تخصیص توسط فرآیند را مشخص می کند
- فضای آدرس: ناحیه ای از حافظه را که فرآیند به آن تعلق دارد را مشخص می کند
تصویر زیر از کتاب فرانسیس ماچادو و لوئیس مایا گرفته شده است:
این اطلاعات برای اجرای یک برنامه ضروری است.
نخ ها چیست؟
یکی thread زیرروال یک برنامه است که کوچکترین واحد اجرایی است که یک سیستم عامل مدیریت می کند و جزء یک فرآیند است..
رشته های مختلف یک فرآیند فرضی می توانند به طور همزمان اجرا شوند (که به زودی متوجه خواهیم شد)، به اشتراک گذاری منابعی مانند حافظه. فرآیندهای مختلف این منابع را به اشتراک نمی گذارند.
تصویر زیر از ویکی پدیا گرفته شده است:
با تفسیر تصویر بالا، میتوانیم آن را استخراج کنیم که یک برنامه بر روی دیسک (حافظه ثانویه، غیر فرار) ذخیره شده است و شامل چندین دستورالعمل است و میتواند در یک یا چند فرآیند نمونهسازی (شروع) شود، و اینها به نوبه خود میتوانند چندین رشته مرتبط داشته باشند. .
I/O bound و CPU bound به چه معناست؟
این دو عبارت در بحث رقابت زیاد ظاهر می شوند و می توانند در پرتغالی با I/O (ورودی/خروجی) و CPU (واحد پردازش مرکزی) ظاهر شوند.
هنگامی که ما در مورد I/O Bound و CPU Bound صحبت می کنیم، در مورد عوامل محدود کننده ای صحبت می کنیم که مانع از اجرای سریعتر یک عملیات بر روی کامپیوتر ما می شود، و ما می توانیم این دو نوع عملیات را در یک پایگاه کد پیدا کنیم.
یک عملیات محدود به CPU به CPU فشرده است و اگر CPU قدرتمندتر باشد، سریعتر اجرا می شود. به عبارت دیگر، اگر از سرعت ساعت 2 گیگاهرتز به 4 گیگاهرتز برویم، احتمالا این عملیات سریعتر اجرا می شود. ما در اینجا در مورد عملیاتی صحبت می کنیم که محاسبات و محاسبات زیادی را انجام می دهند. به عنوان مثال، نحوه محاسبه Pi.
یک عملیات محدود به ورودی/خروجی به سرعت شبکه و سرعت دستگاه های ورودی و خروجی بستگی دارد. درخواست از یک وب سرور یا خواندن یک فایل از دیسک، عملیات محدود به ورودی/خروجی هستند.
هر دو نوع عملیات می توانند از استفاده همزمان سود ببرند.
GIL پایتون چیست؟
GIL یعنی قفل مفسر جهانی، هدف از آن جلوگیری از اجرای همزمان بیش از یک بایت کد دستورالعمل پایتون توسط یک فرآیند پایتون است.. برای اجرای یک رشته، لازم است GIL را “به دست آورید” و در حالی که یک رشته GIL را نگه می دارد، رشته دیگر نمی تواند همزمان آن را بدست آورد. این بدان معنا نیست که ما نمی توانیم بیش از یک رشته در این زمینه داشته باشیم.
در اینجا ما پیاده سازی مرجع پایتون را در نظر می گیریم. CPython پیاده سازی پیش فرض پایتون است، به عنوان مرجعی برای نحوه رفتار زبان استفاده می شود. پیاده سازی های دیگری مانند Jython یا IronPython نیز وجود دارد. GIL در CPython وجود دارد و اخیراً ما یک PEP (پیشنهاد ارتقای پایتون) داشتیم که پیشنهاد میکرد GIL اختیاری شود.
ایده GIL پیشگیری است شرایط مسابقه، که می تواند زمانی ایجاد شود که بیش از یک رشته نیاز به ارجاع همزمان به یک شی پایتون داشته باشند. اگر بیش از یک رشته یک متغیر مشترک را تغییر دهد، آن متغیر ممکن است در حالت غیرمنتظره باشد. تصویر برگرفته از کتاب متیو فاولر:
در تصویر بالا، دو رشته به طور همزمان سعی میکنند تعداد مرجع را افزایش دهند و به جای اینکه تعداد 2 باشد، از آنجایی که هر دو در حال افزایش 1 هستند، نتیجه نهایی 1 را میدهد (هر رشته یک ستون است).
رقابت چیست؟
رقابت در محاسبات زمانی اتفاق می افتد که بیش از یک کار را انجام می دهد، بدون اینکه لزوماً این دو کار را دقیقاً همزمان انجام دهد. نقل قول معروف راب پیک در این زمینه:
رقابت یعنی لیدار با خیلی چیزها همزمان موازی سازی است انجام دادن خیلی چیزها همزمان
به این وضعیت فرضی فکر کنید: اگر قرار است دو کیک درست کنید، می توانید با گرم کردن فر شروع کنید و در این فاصله خمیر کیک اول را آماده کنید. وقتی فر به دمای مناسب رسید، می توانید خمیر کیک اول را در فر قرار دهید و در حالی که منتظر هستید تا کیک در فر بلند شود، خمیر کیک دوم را آماده کنید. ایده رقابت اساساً این است، شما نیازی به بیکار ماندن، گیر کردن، متوقف شدن ندارید، در حالی که منتظر تکمیل یک کار هستید، می توانید یک کار را انجام دهید. سوئیچ و وظایف را تغییر دهید.
در این زمینه ما دو نوع مولتی تسکینگ داریم:
-
چندوظیفه ای مشارکتی: در این مدل در کد نقاطی را که می توانید انجام دهید توضیح می دهیم سوئیچ از وظایف در پایتون این با استفاده از یک حلقه رویداد، یک الگوی طراحی رایج، با استفاده از تنها یک رشته و یک هسته CPU، برای مثال، با استفاده از
asyncio
comasync
هawait
-
چندوظیفه ای پیشگیرانه: در این مدل به سیستم عامل اجازه می دهیم تا کنترل کند سوئیچ. در پایتون این با بیش از یک رشته و یک هسته CPU با استفاده از lib به دست می آید.
threading
تصویر زیر به خلاصه کردن همزمانی در پایتون کمک می کند:
موازی سازی چیست؟
موازی سازی به این معنی است که بیش از یک کار به طور همزمان در حال اجرا است. به عبارت دیگر، موازی گرایی دلالت بر همزمانی (سر و کار با بیش از یک کار) دارد، اما همزمانی به معنای موازی بودن نیست (لزاماً وظایف به طور همزمان به صورت موازی اجرا نمی شوند). برای اینکه موازی سازی امکان پذیر باشد به بیش از یک هسته CPU نیاز داریم.
در پایتون موازی سازی به عنوان مثال با lib به دست می آید multiprocessing
، جایی که ما بیش از یک فرآیند پایتون خواهیم داشت که هر کدام GIL خاص خود را دارند. تصویر به نشان دادن موازی سازی در پایتون کمک می کند:
به کتابخانه asyncio
راههای مختلفی برای دستیابی به همزمانی و موازیسازی در پایتون وجود دارد و بسته به نوع عملیاتی که با آن سروکار داریم، I/O Bound یا CPU، میتوانیم از برخی کتابخانهها برای بهینهسازی کد خود استفاده کنیم. THE asyncio
یک است lib برای دستیابی به همزمانی با استفاده از async
ه await
. از مستندات:
Asyncio به عنوان پایه ای برای چندین چارچوب پایتون ناهمزمان استفاده می شود که شبکه و وب سرورهای با کارایی بالا، کتابخانه های اتصال پایگاه داده، صف های شغلی توزیع شده و غیره را ارائه می دهند.
همانطور که می توانید تصور کنید، این lib برای بهینه سازی وظایف محدود به ورودی/خروجی، که در آن زمان انتظار شبکه، نوشتن دیسک و غیره داریم، مناسب است. در یک عملیات محدود به CPU هیچ انتظاری وجود ندارد، ما فقط به سرعت محاسبه CPU وابسته هستیم.
یک رشته کتابشناسی
یک lib threading
پایتون به ما اجازه می دهد تا بیش از یک رشته را کار کنیمبا این حال، ما همچنان با یک هسته CPU و یک فرآیند پایتون سروکار داریم، و به یاد داشته باشید که این یک مورد چندوظیفه ای پیشگیرانه است که در آن سیستم عامل وظیفه سوئیچینگ را برای ما انجام می دهد. lib همچنین برای بهینه سازی عملیات محدود I/O مفیدتر است.
درباره threading
، وب سایت Real Python چند نکته مهم را آورده است:
از آنجایی که سیستم عامل کنترل زمان توقف یک کار و شروع کار دیگر را دارد، هر داده ای که بین رشته ها به اشتراک گذاشته می شود باید محافظت شود، یا ایمن با نخ. متاسفانه
requests.Session()
این نیست ایمن با نخ. چندین استراتژی برای دسترسی به داده ها وجود دارد ایمن با نخ بسته به اینکه چه داده ای است و چگونه از آن استفاده می کنید. یکی از آنها استفاده از ساختارهای داده است ایمن با نخ به عنوانQueue
از ماژولqueue
پایتون را انجام دهید
ما مستندات را پیدا کردیم queue
اینجا
یک پردازش چندگانه کتابشناسی
درباره lib multiprocessing
در مستندات پایتون:
multiprocessing
بسته ای است که از تولید فرآیندها با استفاده از API مشابه ماژول پشتیبانی می کندthreading
. بستهmultiprocessing
همزمانی محلی و راه دور را ارائه می دهد و به طور موثر GIL را با استفاده از فرآیندهای فرعی به جای نخ ها دور می زند. به همین دلیل است ماژولmultiprocessing
به برنامه نویس اجازه می دهد تا از چندین پردازنده در یک دستگاه استفاده کند.
شایان ذکر است که اجرای بیش از یک فرآیند بر روی هسته های مختلف CPU به معنای غیرفعال کردن GIL نیست، بلکه هر فرآیند دارای GIL خاص خود خواهد بود. با بهره گیری از بیش از یک هسته CPU، به اشتراک گذاری بارهای کاری سنگین CPU بین چندین هسته موجود، lib برای CPU Bound مناسب تر است.
منابع:
فاولر، متیو. همزمانی پایتون با asyncio. انتشارات منینگ، 2022.
ماچادو، فرانسیس برنگر؛ مایا، لوئیز پائولو. معماری سیستم های عامل: شامل تمرینات با شبیه ساز SOSIM و سوالات ENADE. ریودوژانیرو: LTC، 2013.
موضوع (محاسبات) توسط ویکی پدیا، دانشنامه آزاد
سرعت برنامه پایتون خود را با همزمانی پایتون واقعی افزایش دهید