فصل اول: برنامه‌نویسی ناهمگام و تسک‌ها ⏳🔄

در این فصل، ابتدا با مقدمه‌ای بر برنامه‌نویسی ناهمگام آشنا می‌شوید و سپس تسک‌ها (Tasks) و اهمیت آن‌ها بررسی می‌شوند.

درک عملیات ناهمگام 🧠➡️💻

روانشناسان معمولاً انجام یک کار در یک زمان را توصیه می‌کنند، زیرا این کار باعث تمرکز بهتر می‌شود. اما زندگی مدرن پر از مشغله است و پیروی از این توصیه همیشه آسان نیست.

مثالی ساده: مادران شاغل را در نظر بگیرید. آن‌ها صبح‌ها باید چندین کار را قبل از رفتن به محل کار انجام دهند:

این مادران کارها را شروع می‌کنند اما منتظر اتمام یک کار نمی‌مانند؛ بلکه به کار بعدی می‌پردازند و سپس برمی‌گردند تا کار قبلی را بررسی کنند. این روند تا اتمام همه کارها ادامه دارد.

این دقیقاً همان چیزی است که در برنامه‌نویسی ناهمگام اتفاق می‌افتد؛ کارها هم‌زمان یا موازی آغاز می‌شوند و هر کدام در زمان مناسب تکمیل می‌گردند.

این روش چه کمکی می‌کند؟ 🤔⚡

حتی اگر این شیوه را دوست نداشته باشید، مواقعی وجود دارد که اجتناب از آن ممکن نیست.
مثال ساده: اگر صبح دیر بیدار شوید اما نمی‌خواهید برای مدرسه یا محل کار دیر کنید، تنها گزینه این است که چند کار را هم‌زمان انجام دهید (ناهمگام).

حالا بیایید درباره برنامه‌نویسی صحبت کنیم. فرض کنید در حال توسعه برنامه‌ای هستید که همه کارها، حتی کارهای طولانی‌مدت (مثلاً دانلود یک فایل حجیم از اینترنت)، روی رشته اصلی برنامه (Main Thread) اجرا می‌شوند.

راه‌حل چیست؟

نتیجه:

سناریوهای مناسب استفاده از برنامه‌نویسی ناهمگام 🎯

البته همه موقعیت‌ها مناسب کار ناهمگام نیستند.

پس نتیجه می‌گیریم که:
هر موقعیتی مناسب کار ناهمگام یا موازی نیست.

اما سؤال مهم: چه زمانی باید از برنامه‌نویسی ناهمگام استفاده کنیم؟

موارد رایج:

پرسش و پاسخ ❓💬

سؤال 1.1: به نظر می‌رسد برنامه‌نویسی ناهمگام باعث افزایش پیچیدگی کد می‌شود. آیا این مشکل نیست؟ 🤔

بله، درست است که ممکن است پیچیدگی کد افزایش یابد.
اما تصور کنید برای ایجاد یک رابط کاربری (UI) پاسخگوتر، یک عملیات طولانی را به رشته پس‌زمینه منتقل می‌کنید.

سؤال 1.2: آیا برنامه‌نویسی ناهمگام و برنامه‌نویسی موازی یکی هستند؟ ⚡👥

بیایید چند مثال واقعی بررسی کنیم:

تعریف رسمی:

مجله Visual Studio این موضوع را این‌گونه خلاصه کرده است:

برنامه‌نویسی ناهمگام روشی از برنامه‌نویسی موازی است که در آن یک واحد کاری به‌صورت جداگانه از رشته اصلی برنامه اجرا می‌شود و پس از اتمام، شکست یا پیشرفت کار، رشته فراخوان را مطلع می‌کند.

الگوهای برنامه‌نویسی 🧩💡

بدون شک، برنامه‌نویسی ناهمگام سخت است، اما در گذشته بسیار سخت‌تر بود. در آن زمان، توسعه‌دهندگان گزینه‌های زیر را داشتند:

اما این روش‌ها برای توسعه‌های جدید توصیه نمی‌شوند.

الگوی پیشنهادی ✨✅

پس، الگوی پیشنهادی چیست؟
به لینک رسمی مایکروسافت مراجعه کنید:
https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap

مایکروسافت چنین توضیح می‌دهد:

در .NET، الگوی ناهمگام مبتنی بر Task (TAP)، الگوی توصیه‌شده برای توسعه‌های جدید است.
این الگو بر اساس Task و Task در فضای نام System.Threading.Tasks است که برای نمایش عملیات ناهمگام استفاده می‌شوند.

توجه:

این کتاب به‌صورت عمیق وارد TAP نمی‌شود، زیرا اکثر پیاده‌سازی‌های TAP شامل کلیدواژه‌های async و await هستند که در کتابچه دیگری از این مجموعه بررسی خواهند شد.

این کتاب صرفاً روی برنامه‌نویسی با Task بدون استفاده از async و await تمرکز دارد.

کتابخانه موازی‌سازی وظایف (Task Parallel Library - TPL) ⚡🧵

در برنامه‌نویسی با Task، زیاد با اصطلاح Task Parallel Library (TPL) مواجه می‌شوید. اجازه بدهید یک مرور سریع داشته باشیم:

TPL مجموعه‌ای از نوع‌ها (Types) و APIهای عمومی را ارائه می‌دهد که در فضاهای نام زیر قرار دارند:

جالب است بدانید فضای نام System.Threading.Tasks در .NET 4 معرفی شد و مایکروسافت بیان کرده است:

"TPL، API ترجیحی برای نوشتن کدهای چندریسمانی (Multi-threaded)، ناهمگام (Asynchronous) و موازی (Parallel) در .NET است."

https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl

به همین دلیل، این کتاب بحث را با Taskها شروع می‌کند، چون آنها پایه و اساس TPL هستند.

پشت‌صحنه TPL 🔍

جالب است بدانید در پشت‌صحنه، Taskها در صف ThreadPool قرار می‌گیرند. این ThreadPool تعداد رشته‌ها را تعیین و تنظیم می‌کند و با استفاده از الگوریتم‌های مخصوص، بار کاری را متعادل می‌سازد تا بیشترین بازدهی حاصل شود.

TPL چگونه کمک می‌کند؟ 🤔

TPL در سناریوهای متنوعی مفید است. به عنوان مثال، می‌توانید از آن برای کنترل هر یک از موارد زیر استفاده کنید:

فعلاً همین اندازه کافی است که بدانید:
TPL فرآیندهای چندریسمانی را ساده‌تر می‌کند و به شما کمک می‌کند کدهای پرفورمنس بالا بنویسید بدون اینکه درگیر جزئیات پیچیده Threading و بخش‌های سطح پایین شوید.

مایکروسافت این موضوع را به‌خوبی خلاصه کرده است:

هدف TPL این است که با ساده‌سازی اضافه کردن موازی‌سازی و هم‌زمانی به برنامه‌ها، بهره‌وری توسعه‌دهندگان را افزایش دهد.

https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl

معرفی Task ها در TPL 🔹

همان‌طور که دیدید، TPL بر اساس مفهوم Task ساخته شده است. حال سؤال این است:
Task چیست؟

می‌توانید Task را مانند یک بلاک کد که یک واحد کار (Unit of Work) را نشان می‌دهد در نظر بگیرید. شما می‌توانید به زمان‌بند (Scheduler) اطلاع دهید که این بلاک کد می‌تواند روی یک رشته‌ی جداگانه (Separate Thread) اجرا شود، در حالی که رشته‌ی اصلی (Main Thread) به کار خود ادامه می‌دهد.

به عنوان مثال، قطعه کد زیر را ببینید:

static void PrintNumbersTask()
{
    WriteLine("Starts printing the numbers.");
    // Continues the work
    WriteLine("The task is completed.");
}

این متد یک واحد کاری است که می‌تواند روی یک رشته‌ی جداگانه اجرا شود.

سناریوهای مفید استفاده از Taskها 💡

برخی از سناریوهای رایج استفاده از Task شامل موارد زیر است:

پرسش و پاسخ ❓💬

سؤال 1.3: مزایای استفاده از Task نسبت به Thread چیست؟ ⚡🧵

مزایای رایج استفاده از Task شامل موارد زیر است:

سؤال 1.4: پیشرفت‌های اساسی Task نسبت به مدل‌های برنامه‌نویسی قبلی چه بود؟ 🚀

مزایای زیادی وجود دارد. پس از اتمام این کتاب، این مزایا برایتان واضح خواهد شد.

فعلاً می‌توان گفت:

خلاصه فصل ۱ 📚

این فصل با بحث برنامه‌نویسی ناهمگام و کاربردهای آن در دنیای امروزی آغاز شد. سپس TPL و نقش Taskها در برنامه‌نویسی ناهمگام معرفی شد.

به طور خلاصه، این فصل به سوالات زیر پاسخ داد:

برای سنجش درک خود، تمرین‌های زیر را انجام دهید:

E1.1 درست/نادرست (True/False):

i) در .NET، الگوی ناهمگام مبتنی بر Task، الگوی توصیه‌شده فعلی برای برنامه‌نویسی ناهمگام است. ✅

ii) اجرای ناهمگام همیشه سریع‌تر از اجرای همزمان (Synchronous) مربوطه است. ❌

iii) انجام یک محاسبه زمان‌بر نمونه‌ای از عملیات CPU-bound است که می‌تواند از برنامه‌نویسی ناهمگام بهره ببرد. ✅

iv) دانلود یک فایل بزرگ از اینترنت نمونه‌ای رایج از عملیات I/O-bound است که می‌تواند از برنامه‌نویسی ناهمگام بهره ببرد. ✅

E1.2 حداقل دو مزیت اصلی برنامه‌نویسی ناهمگام را بیان کنید:

راه‌حل تمرین‌ها ✅💡

در اینجا نمونه‌ای از پاسخ‌های تمرین‌های فصل ۱ ارائه شده است:

E1.1

پاسخ‌ها به صورت Bold مشخص شده‌اند:

i) در .NET، الگوی ناهمگام مبتنی بر Task، الگوی توصیه‌شده فعلی برای برنامه‌نویسی ناهمگام است. [True ✅]

ii) اجرای ناهمگام همیشه سریع‌تر از اجرای همزمان (Synchronous) مربوطه است. [False ❌]

iii) انجام یک محاسبه زمان‌بر نمونه‌ای از عملیات CPU-bound است که می‌تواند از برنامه‌نویسی ناهمگام بهره ببرد. [True ✅]

iv) دانلود یک فایل بزرگ از اینترنت نمونه‌ای رایج از عملیات I/O-bound است که می‌تواند از برنامه‌نویسی ناهمگام بهره ببرد. [True ✅]

E1.2

دو مزیت اصلی استفاده از برنامه‌نویسی ناهمگام عبارتند از: