چرا برنامهنویسی async وجود دارد؟
· 5 دقیقه مطالعهمهندسی توسعه نرمافزار #csharp #dotnet #async
یک برنامه بارها باید منتظر کاری بماند که خودش نمیتواند انجامش دهد.
از یک سرویس هواشناسی پیشبینی هوا میخواهد، فایلی را از دیسک میخواند، منتظر نتیجهی کوئری دیتابیس میماند یا به سیستم دیگری پیام میفرستد و پاسخ میخواهد. هیچکدام از اینها محاسبه نیست؛ برنامه کاری را از دستگاه یا سرویس دیگری خواسته و پاسخ هنوز آماده نیست.
برنامهنویسی async برای این است که این انتظار، باقی برنامه را متوقف نکند.
انتظار و محاسبه دو نوع کار متفاوتاند
محاسبه درون خود برنامه اتفاق میافتد: جمع کردن اعداد، اعتبارسنجی ورودی، فیلتر کردن یک لیست در حافظه یا قالببندی متن. CPU میتواند این کارها را همان لحظه انجام دهد.
I/O با دیتابیس، شبکه، فایلسیستم، timer یا سرویس راه دور سروکار دارد. برنامه عملیات را شروع میکند، اما نمیتواند تعیین کند سیستم بیرونی چه زمانی کارش را تمام میکند. این عملیاتها را معمولاً I/O-bound مینامند، چون زمانشان بیشتر به چیزی خارج از محاسبهی فعلی وابسته است.[2]
همین تفاوت، طراحی درست را عوض میکند. وقتی ماشینحساب یک محاسبهی کوتاه انجام میدهد، انتظار کشیدن معنایی ندارد؛ اما وقتی درخواست هواشناسی در شبکه در رفتوآمد است، برنامه یک انتخاب دارد: تا رسیدن پاسخ blocked بماند یا کنترل را واگذار کند و سراغ کارهای دیگر برود.
یک درخواست، دو طراحی
یک صفحهی هواشناسی را تصور کنید. کاربر شهری را انتخاب میکند و برنامه پیشبینی هوا را از یک API راه دور میخواهد.
در طراحی blocking، مسیر اجرا همانجا منتظر پاسخ API میماند. رابط کاربری دیگر نمیتواند به کارهایش رسیدگی کند و در یک برنامهی سرور هم، همان مسیر اجرا تا پایان رسیدگی به درخواست، برای درخواست ورودی دیگری آزاد نیست.
در طراحی async، برنامه درخواست API را شروع میکند و تا آماده شدن پاسخ کنترل را واگذار میکند؛ پس از رسیدن پاسخ، ادامهی همان عملیات را انجام میدهد. زمان لازم برای شبکه همان است، اما برنامه آن زمان را بیکار نمیماند.[1]
تفاوت در یک خط زمانی
| زمان | thread مسدودشده | عملیات async |
|---|---|---|
| ۰ میلیثانیه | درخواست هواشناسی را شروع میکند. | درخواست هواشناسی را شروع میکند. |
| ۱ تا ۵۰۰ میلیثانیه | تا پاسخ API راه دور، مسدود میماند. | تا آماده شدن پاسخ کنترل را واگذار میکند و کار آمادهی دیگر میتواند ادامه پیدا کند. |
| ۵۰۰ میلیثانیه | پاسخ را میگیرد و ادامه میدهد. | عملیات اولیه را از سر میگیرد و ادامه میدهد. |
زمان رسیدن پاسخ در اختیار API راه دور است؛ بنابراین هیچکدام از این دو طراحی، پیشبینی هوا را زودتر آماده نمیکند. تفاوت async در اتفاقی است که در مدت انتظار میافتد.
پاسخگویی در برنامههای تعاملی
رابط کاربری باید ورودی را پردازش کند، دوباره رسم شود و وضعیت کار را نشان دهد. اگر هنگام انتظار برای یک درخواست راه دور blocked بماند، ممکن است کاربر روی دکمه کلیک کند و احساس کند هیچ اتفاقی نیفتاده است. صفحه فریز به نظر میرسد، در حالی که برنامه فقط منتظر پاسخ است.
async به برنامه فرصت میدهد در مدت انتظار، رویدادهایی را که آمادهی پردازشاند پردازش کند. کاربر همچنان میتواند با رابط کاربری تعامل داشته باشد و برنامه پس از آماده شدن پاسخ، صفحه را بهروزرسانی میکند. MDN مدل کلی asynchronous را هم به همین شکل توضیح میدهد: یک درخواست میتواند در زمان انتظار برای پاسخ، مانع انجام کارهای دیگر نشود.[1]
توان عملیاتی در برنامههای سرور
یک سرور معمولاً همزمان به درخواستهای زیادی رسیدگی میکند. بعضی از آنها پیش از پاسخ دادن باید از دیتابیس داده بگیرند یا سرویسی دیگر را فراخوانی کنند.
اگر هر درخواست در تمام انتظارهای بیرونی blocked بماند، ظرفیت کمتری برای رسیدگی به کارهای تازه در دسترس میماند. با افزایش تعداد درخواستهای منتظر، زمان پاسخ هم میتواند بیشتر شود.
I/O غیرهمگام کمک میکند سرور برای درخواستی که فقط منتظر سیستم دیگری است، منابع اجرایی را اشغال نکند. راهنمای ASP.NET Core هم به همین دلیل توصیه میکند از فراخوانیهای blocking دوری کنید: وقتی درخواستها برای I/O بهصورت synchronous معطل نمیمانند، ظرفیت موجود بهتر استفاده میشود.[3]
async محدودیتهای واقعی را حذف نمیکند. دیتابیس، API راه دور، اتصال شبکه و حافظه همچنان میتوانند گلوگاه باشند. async فقط کمک میکند منابع اجرایی برنامه هنگام انتظار بیرونی هدر نروند.
async چه زمانی مفید است؟
async وقتی انتخاب خوبی است که عملیات، زمان قابل توجهی منتظر I/O میماند:
- فراخوانی یک API با HTTP
- اجرای کوئری دیتابیس
- خواندن یا نوشتن فایل
- دریافت پیام از صف پیام
- انتظار برای timer یا delay
اینکه بتوان یک متد را asynchronous کرد، بهتنهایی دلیل کافی نیست. یک محاسبهی کوتاه که همهی دادههایش از قبل در حافظه است، انتظار بیرونی ندارد که برنامه در آن فاصله کار دیگری انجام دهد.
async چه تغییری میدهد؟
برنامهنویسی async به برنامه اجازه میدهد هنگام انتظار برای کار بیرونی، کار دیگری انجام دهد. این کار رابطهای تعاملی را پاسخگو نگه میدارد و به سرورها کمک میکند از ظرفیت موجود بهتر استفاده کنند.