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

فرآیندها دو نوع هستند Sync و Async

Sync

یک فرآیند sync وابسته به یک فرآیند دیگه هست یعنی اینکه باید با اون فرآیند sync یا هماهنگ باشه و باید منتظر اتمام اون فرآیند باشه بعد کار خودش رو شروع کنه برای مثال فرآیند ذخیره پست در همین سیستم وردپرس رو در نظر بگیرید در این فرآیند برنامه بعد از پردازش، پست  رو به دیتابیس میفرسته و حالا باید منتظر بمونه تا فرآیند دیتابیس پیام موفقیت یا عدم موفقیت رو برگردونه تا کارش رو ادامه بده و پیام نهایی رو به کاربر نشون بده پس این دو فرآیند باید با هم sync باشن.

Async

یک سری از فرآیند ها،  وابسته به فرآیند دیگه ای نیستند و بدون نیاز به اونها کارشون رو انجام میدن برای مثال دو فرآیند افزودن پست و لوگین کردن.

این دو فرآیند میتونن به صورت مستقل از هم اجرا بشن و نیازی نیست که sync باشن یا برای یه مثال دیگه فرآیندی که یک صفحه وب مشخص رو پردازش میکنه رو در نظر بگیرید، هرچند تا از این فرآیند میتونه به صورت مستقل از هم اجرا بشن چون در هر لحظه یک صفحه وب خاص در حال پردازش شدن هست که به فرایند دیگه ای از همین جنس که ادرسش فرق داره ارتباطی نداره.

 

Sync یا Async بودن یک فرآیند به ماهیت و ساختار اون فرآیند و عملیاتی که انجام میده بستگی داره نه چیز دیگه ای

 

حالا اگه فرآیند های شما قابلیت اجرای مستقل از هم رو داشته باشه یعنی async باشن این قابلیت رو دارن که به صورت همزمان یا concurrent  اجرا بشه

Concurrency (Simultaenously)

concurrency مدل اجرای چند فرآیند به صورت همزمان هست یعنی برنامه رو طوری ساختار دهی کنیم که فرایند های async امکان اجرای همزمان رو داشته باشن دقت کنید که گفتم این امکان براشون باشه که همزمان اجرا بشن برای مثال اگه چند فرایند async رو باهم اجرا کنیم این برنامه concurrent میشه نه اینکه حتما همزمان اجرا بشن حالا اینجا رو دقت کنید/

Parallelism

موازی سازی مرحله بعدی هست یعنی فرآیندهایی که به صورت concurrent ساختار دهی شدن حالا به صورت موازی و همزمان اجرا بشن

 

پس Concurreny مربوط به ساختار برنامه هست و Parallelism مربوط به اجرا

 

برای مثال در نظر بگیرید که تعداد اتصال های فعال یک دیتابیس فقط یه دونه میتون باشه حالا فرض کنید فرآیندی هست که به دیتابیس وصل میشه و مقداری رو میخونه.

حالا اگه ما طوری برنامه رو طوری ساختار دهی کنیم که ۴ تا از این فرآیندها به صورت مستقل بتونن اجرا بشن ما این برنامه رو به صورت concurrent در اوردیم ولی در هر لحظه به خاطر محدودیتی که هست فقط یک فرآیند میتونه به دیتابیس وصل بشه یعنی در هر لحظه عملا یک فرایند میتونه کارش رو انجام بده حالا اگه ما تعداد اتصال های مجاز رو ۳ تا کنیم در هر لحظه ۳ تا فرآیند میتونن اجرا شن که این میشه موازی سازی یا parallelism.

یک مثال دیگه، فرآیند دریافت بلیط رو در نظر بگیرید اگه یک باجه بلیط فروشی داشته باشیم و برای دریافت بلیط از باجه ۴ صف تشکیل بدیم این سیستم رو به صورت concurrent  ساختار دهی کردیم ولی در هر لحظه فقط یک نفر میتونه بلیط بگیره.

اگه تعداد باجه ها رو بیشتر کنیم و ۳ تاش کنیم حالا به صورت موازی و همزمان بلیط فروشی داره انجام میشه و در هر لحظه به ۳ نفر به صورت همزمان بلیط فروخته میشه.

در پایتون برای concurrent کردن هم میتونید از thread استفاده کنید هم از process

در پایتون میشه از ماژول های multithreading و multiprocessing استفاده کرد که کمی قدیمی شدن در نسخه ۳ این ماژول ها با api بهتر و تحت عنوان concurrent.futures قرار داده شده که من با اونها کار میکنم البته ماهیتشون یکی هست ولی api شون بهتر شده.

حالا برای اینکه تصمیم بگیرید که از thread استفاده کنید یا process یک قانون کلی هست که میگه اگه اون فرآیند خیلی باید منتظر ورودی باشه از thread استفاده کنید و اگه خیلی از cpu استفاده میکنه از process استفاده کنید

یک فرآیند ساده که میتونه async باشه و در متن بالا به اون اشاره شد پردازش صفحه وب هست حالا برنامه ای رو در نظر بگیرید که ۱۰۰ ادرس رو میخواد پردازش کنه یعنی ۱۰۰ تا thread باید بسازید یا ۱۰۰ تا process حالا اینکه اینها به صورت همزمان اجرا بشن بستگی به سخت افزارتون داره (در این مورد خاص که خیلی ساده هست حتما میشه)

برای اجرای این برنامه با thread به صورت زیر عمل میکنیم

 

ThreadPoolExecutor یک مقدار max_workers میگیره که مشخص میکنه با چه تعداد thread این عملیات ها رو اجرا کنه اگه مقداری ندید مقدار پیش فرضش تعداد processor های cpu  ضرب در  ۵ خواهد بود.

با کد زیر هم میتونید تعداد processor های cpu رو به دست بیارید

دقت کنید که منظور کل thread ها برای اجرا برنامه هست نه تعداد thread های همزمان.

در  مثال بالا با استفاده از submit پردازش ۱۰۰ صفحه رو شروع میکنیم و در مرحله بعد برای اینکه از اتمام کار پردازش تمام ۱۰۰ صفحه مطمئن بشیم از تابع as_completed استفاده میکنیم این تابع ارایه ای از متغیر future رو میگیره و تا تموم شدن تمام فرایندها اجرای کد رو متوقف میکنه

متغیر future یک متغیر خاص هست و همونطور که از اسمش معلوم هنوز مقدار کامل نداره

 

 اجرای future.result فقط نتیجه رو نشون میده و کار دیگه ای نمیکنه این تابع as_completed هست که تضمین میکنه کار یک thread تموم شده

 

یک راه دیگه برای اجرای این برنامه استفاده از تابع map هست این تابع مانند تابع map خود پایتون هست که یک تابع رو با ارگومانی که در اختیارش گذاشتیم اجرا میکنه

وقتی از تابع map استفاده میکنید تا تموم شدن تمام فرایندها برنامه به خط بعدی نمیره یعنی قبل از  رسیدن برنامه به حلقه تمام فرآیندها انجام شده

تفاوت مهم بین submit و map این هست که وقتی از submit و در ادامه اون از as_completed استفاده میکنید نتایجی رو زودتر میگیرید که زودتر تموم شدن ولی در map نتایح رو بر اساس ترتیبی که دادید میگیرید برای مثال اگه ادرس ها رو در لیست (که در اونها ترتیب مقادیر حفظ میشه ) به map ارسال کرده باشید (مثل بالا) نتایج رو به همون ترتیب هم میگیرید.

البته استفاده از این دو، به نوع برنامه و کاری که میخواید انجام بدید بستگی داره

برای اینکه همین برنامه رو با process اجرا کنیم به صورت زیر باید عمل کنیم

ProcessPoolExecutor یک مقدار max_workers میگیره که مشخص میکنه با چه تعداد process این عملیات ها رو اجرا کنه اگه مقداری ندید مقدار پیش فرض تعداد processor های cpu خواهد بود.

دقت کنید که منظور کل process ها برای اجرای برنامه هست نه تعداد process های همزمان.

روش دوم هم استفاده از تابع map هست

تابع map وقتی با process اجرا بشه یک آرگومان دیگه به نام chunksize میگیره که مشخص میکنه در هر بار چند تا فرایند برای اجرا استارت بخوره.

مقدار پیش فرض این آرگومان ۱ هست یعنی دونه دونه اجرای تابع requests.get برای هر url پشت سر هم به صورت ترتیبی ارسال بشه اگه برای مثال ۱۰ بزارید تابع map به صورت همزمان ۱۰ تا ۱۰ تا آدرس میگیره و به صورت گروهی درخواست اجرای این تابع رو ارسال میکنه تنظیم این مقدار وقتی از process استفاده میکنید میتونه تاثیر زیادی در افزایش سرعت برنامتون داشته باشه. (دقت کنید که منظور ارسال درخواست اجرا هست نه خود اجرا)

هر برنامه ای که خواستید به صورت همزمان پیاده سازی کنید حتما هر دو روش رو تست کنید با مقادیر مختلف و توابع مختلف تا بهترین حالت رو پیدا کنید.

خبرنامه

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *