Concurrency به این معنیه که دو یا چند تسک، استارت، اجرا و تموم میشن با همپوشانی زمانی بین اونها، یعنی هیچ تسکی بلاک نمیشه تا تسک دیگه اجرا بشه. مثل پیاده سازی async .
مفهومی هم به اسم parallelism وجود داره که مربوط به وقتی میشه که واقعا تسک ها به صورت همزمان در حال اجرا هستند. برای اینکه parallelism داشته باشیم، نیاز داریم به سخت افزارهایی که بتونن چند کارو همزمان انجام بدن. CPU های چند هسته ای، یا چند CPU یا چند کامپیوتر متصل به هم.
قطعا نرم افزاری که برای دنیای واقعی بخایم بنویسیم باید concurrent باشه، چون تسک هایی که توی سیستم رخ میده، مثل کال کردن یک سرویس خارجی، فچ کردن دیتای دیتابیس، interact کاربر با یوزر اینترفیس، اینها نمیتونه سریال انجام بشه و سیستم قفل بشه بابت انجام هر کدوم از این تسکها، و اگر concurrent پیاده سازی نکنیم، هم کیفیت اجرایی سیستم به شدت پایین میاد هم نمیتونیم از حداکثر توان سخت افزار بهره ببریم و هرز رفتیم.
تو این فصل میخایم به concurrency و parallelism بپردازیم.
درس 33: شکستن اتصال زمانی Breaking Temporal Coupling
زمان معمولا وجه نادیده گرفته شده ایه توی معماری نرم افزار. تنها زمانی که ما درگیرش میشیم، زمان بندی کلی پروژه است که کی تاریخ رسوندن یک فیچره، کی تاریخ لانچ یک ماژوله و ...، این زمان در اینجا مورد بحث ما نیست.
در اینجا، ما در مورد نقش زمان توی طراحی هر کدوم از عنصرهای نرم افزار صحبت میکنیم، دو تا جنبه مهم وجود داره: concurrency و ordering (ترتیب و موقعیت نسبی چیزها)
ما معمولا از این جنبه ها، به مسئله نگاه و فکر نمیکنیم، عموما برنامه نویس ها وقتی میشینن و به طراحی و معماری یک سیستم فکر میکنند، به شکل خطی فکر میکنند(linear)، اول این اجرا بشه، بعد اون اجرا بشه ، بعد ...
اما این مدلی فکر کردن به temporal coupling ختم میشه، وابستگی در زمان (coupling in time).(قبلا گفته شد هر مدلی از coupling بده، چون وابستگی ها توی سیستم باعث میشن که تغییرات شکننده و سخت بشه، و کلا زندگیه سیستمو سخت میکنه، کلا به این کلمه coupling حساس باشین، راجعش زیاد بخونید و راهکارهایی که کمش کنید توی سیستم)
مثلا: متود A باید کال بشه قبل از متود B، فقط یک گزارش در یک زمان میتونه در حال اجرا باشه، شما برای ui باید صبر کنید تا بازسازی بشه قبل اینکه باتن کلیک رسپانسش بیاد و ... این مدلی نه انعطاف وجود داره و نه واقع گرایانه است.
LOOKING FOR CONCURRENCY
توی خیلی از پروژه ها برای اینکه تحلیل کنیم سیستمو و به مدل برسیم برای طراحی، نیاز داریم تا ورک فلوهای سیستم رو در بیاریم، توی این ورک فلوها مشخص میشه چه کارهایی دقیقا باید همزمان رخ بده و یا ترتیب دقیق اجرا چی باشه. یکی از ابزارهایی که برای این کار استفاده میشه activity diagram ها هستن.
یک دیاگرام اکتیویتی از یک سری اکشن ها که به شکل مستطیل نمایش داده میشن و یک سری خطوط که اکشن ها رو بهم وصل میکنه و ترتیب اجرا رو مشخص میکنه، تشکیل داده میشن. همچنین یکسری خطهای synchronization bar وجود داره، که مشخص میکنه وقتی چند تا تسک اجراشون تموم شد، اونوقت تسک بعد از این bar اجرا بشه. این مدل نمودار خیلی بهتون کمک میکنه تا عملیات های پارالل رو دیتکت کنید.
به عنوان مثال یک سیستم رباتیک برای ساخت یک شیک بستنی در نظربگیرید، مراحل ساختش به این شکله:
1. Open blender
2. Open piña colada mix
3. Put mix in blender
4. Measure 1/2 cup white rum
5. Pour in rum
6. Add 2 cups of ice
7. Close blender
8. Liquefy for 1 minute
9. Open blender
10. Get glasses
11. Get pink umbrellas
12. Serve
قطعا یک بارتندر اگر بخاد مراحلو به همین ترتیب و پشت سر هم اجرا کنه، اخراجه. چون مبرهنه که خیلی از مراحلو میشه همزمان انجام داد و معطل یک چیز نشیم و همزمان که داره یک کاری انجام میشه، یک کاره دیگه رو هم جلو ببریم و ...
اکتیویتی دیاگرام این مسئله به این شکله:
طبق این دیاگرام و همچنین چیزی که توی واقعیت هم توسط یک بارتندر انسان انجام میشه، تسک هایی مثل 1 2 4 10 و 11 میتونن همزمان اجرا بشن، و بعدش تسک های 3 5 و 6 میتونن بعدش پارالل اجرا بشن.
OPPORTUNITIES FOR CONCURRENCY
اکتیویتی دیاگرام ها مناطق مستعد برای concurrency رو نشون میدن، اما در مورد اینکه ایا اون نقاط ارزش این مدل پیاده سازی رو دارند یا نه، چیزی رو نشون نمیدن. مثلا توی مثال شیک بستنی، یک بارتندر باید 5 تا دست داشته باشه که بتونه تسک های اولیه رو همزمان انجام بده. اینجاست که پای design میاد وسط، وقتی به تسک ها نگاه میکنیم، و مطلع باشیم از اون فعالیت، در مثال قبل تسک 8 liquify، یک دقیقه طول میکشه، طی اون زمان بارتندر میتونه لیوان و بگیره(تسک10) و چتر صورتی رم جور کنه(تسک11)، تازه شاید برای تسک مشتری دیگه ای هم وقت داشته باشه اون وسط. ما دنبال تسک هایی میگردیم توی دیزاین concurrency که بیشتر طول میکشه اجراشون، مثلا کوئری سنگین دیتابیس، کال کردن سرویس خارجی، منتظر بودن برای ورودی کاربر و .. همه اینا پتانسیل هایی رو ایجاد میکنه که از سی پی یو بهینه تر کار بکشیم و کیفیت بهتری ارائه بدیم.
OPPORTUNITIES FOR PARALLELISM
اینو همیشه بخاطر بسپارید همزمانی(concurrency) یک مکانیزم نرم افزاریه و موازی سازی(parallelism) یک عملیات سخت افزاری، اگر سی پی یو چند هسته ای دارید یا از چندین سی پی یوی لوکال یا ریموت استفاده میکنید، میتونید کارها رو بشکنید روی کورهای مختلف پردازنده ها تا سرعت انجام کارها رو کاهش بدید.
معمولا جاهایی ایده آله که از پاراللیسم بریم که کارهایی که میخایم انجام بدیم از هم مستقلند و به هم وابستگی ندارن و برای هم منتظر نمیشن. پترن عمومیش اینجوری که کارهای بزرگو بشکنید به کارهای کوچیک مستقل، اونها رو به صورت پارالل پردازش کنید و بعد هم خروجی شون رو ترکیب کنید تا به نتیجه مطلوب برسید.
DENTIFYING OPPORTUNITIES IS THE EASY PART
معمولا راحت ترین قسمت کار، شناسایی جاهایی که میتونیم از همزمانی یا موازی سازی استفاده کنیم، و قسمت مهمتر و سخت ترش هم میشه اینکه چجوری این رو به صورت امن پیاده سازی کنیم، که مفصل توی درسهای بعد بررسیش میکنیم.
دروس مرتبط: 10, 26, 28, 36
منبع کانال تلگرامی: https://t.me/pragmaticprogrammer_fa