جدیدترین-توضیحات-بلاگ-مایکروسافت-دریاره-ConfigureAwaitReviewed by کارشناسان.نت on December 16Rating:5

اخیرا" مطلبی با عنوان ConfigureAwait FAQ در بلاگ .NET به قلم جناب آقای Stephen Toub قرار گرفته است که به یک سری از سوالات پر درخواست راجع به ConfigureAwait پاسخ می دهد که به شخصه برای خود من بسیار جالب بود و برای همین تصمیم گرفتم تجربه خودم را در قالب پاسخ های ایشان در این مقاله بیان کنم.قبل از سوالات این مقاله اول با اصل موضوع یعنی ConfigureAwait بیشتر آشنا بشویم.

بیش تر از هفت سال پیش بود که الگوی async/await به .NET اضافه شد تا برنامه نویسی async ساده تر انجام شود و این واقعا" جواب داد ، اما همیشه یک دستور برای خود من شبه داشت و آن دستور چیزی نیست جز ConfigureAwait.

اولین سوال اینه که کی باید از ConfigureAwait(false) و کی باید از ConfigureAwait(true) استفاده کرد ، جواب شاید کمی گیج کننده باشد ولی در اصل ConfigureAwait(true) هیچ کاری انجام نمی دهد و دقیقا" برابر با عدم استفاده از ConfigureAwait می باشد و تنها دستور کاربردی ConfigureAwait(false) می باشد ، اما اینکه چرا از یک متغییر bool به این منظور استفاده شده است به علت این است که به توان در RunTime درباره استفاده یا عدم استفاده از این دستور تصمیم گرفت.

همانطور که می دانید دستور async/await باعث می شود تا اجرای یک قطعه کد بر روی Thread دیگر اجرا شود و خروجی به Thread صدا کننده باز گردد بدون متوقف کردن Thread صدا زننده قطعه کد ، کاری که دستور ConfigureAwait(false) انجام می دهد عدم بازگشت SynchronizationContext به Thread صدا زننده می باشد که این موجب مقدار کوچکی بهبود در performance اجرای کد می شود. البته دقت داشته باشید که این دستور مانع jump به Thread صدا زننده نمی شود بلکه فقط مانع انتقال SynchronizationContext می شود بنابراین بهبود performance خیلی کوچک ولی به هر حال قابل اندازه گیریی است.

اما سوال اصلی ، کی باید از ConfigureAwait(false) استفاده کرد و کی نباید از آن استفاده کرد ؟

قبل از پاسخ به این سوال اجازه بدهید برگردیم به مقاله و علاوه بر پاسخ این سوال ، پاسخ سوالات دیگر هم ببینیم:

یک از جالبترین سوالات این است که آیا واقعا" درست هست که نیازی به استفاده از ConfigureAwait(false) در .NET Core نمی باشد؟

پاسخ : خیر. دقیقا" به همان دلیلی که باید از  ConfigureAwait(false) در .NET Framework استفاده کرد به همان دلیل باید در .NET Core استفاده کرد البته با یک تفاوت ، هر محیط SynchronizationContext خاص خودش را دارد مثلا" ASP.NET کلاسیک بر روی .NET Framework دارای SynchronizationContext خاص خودش می باشد و Windows Forms دارای SynchronizationContext خاص خودش می باشد و Windows Presentation Foundation (WPF) دارای SynchronizationContext خاص خودش می باشد اما در مقابل .NET Core دارای SynchronizationContext نمی باشد که در نتیجه نیاز به استفاده از ConfigureAwait(false) را کاهش می دهد اما این هیچ وقت به معنای این نیست که به طور کامل نیاز به استفاده از ConfigureAwait(false) نمی باشد ، زیرا ممکن است کد یک برنامه نویس دیگر کد شما را استفاده کند یا شما از library که داری SynchronizationContext یا TaskScheduler مخصوص خود باشند در کدتان استفاده کنید و در نتیجه در چنین مواردی می توانید از ConfigureAwait(false) استفاده کنید.

سوال جالب دیگه درباره یکی از راههای جایگزین دستور ConfigureAwait(false) هست که در اینترنت خیلی پرطرف داره ، آیا می توانم از دستور SynchronizationContext.SetSynchronizationContext به منظور عدم استفاده از ConfigureAwait(false) استفاده کنم به شکل زیر؟

 

SynchronizationContext old = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
try
{
    await t;
}
finally { SynchronizationContext.SetSynchronizationContext(old); }

پاسخ: خیر. چون عملا" هیچ تضمینی وجود نداره که await دقیقا" به همون Thread ایی که از آن صدا زده شده است برگردد که بتوان SynchronizationContext را ریست کرد  ، زیرا بازگشت به انتخاب ThreadPool خواهد بود که می تواند لزوما" همان Orginal Thread نباشد.

تعداد سوالات خیلی بیشتری در این مقاله وجود داره که از حوصله این مقاله خارج هست ولی خواندن مقاله ConfigureAwait FAQ را حتما" توصیه می کنم.

اما برگردیم به سوال اصلی ، کی باید از ConfigureAwait(false) استفاده کرد و کی نباید از آن استفاده کرد ؟

من پاسخ را به دو بخش اصلی تقسیم می کنم: 1 - app-level code و 2 - general-purpose library code

1 - app-level code:

این نوع کد شامل برنامه های روتینی هستند که نوشته می شوند مثل یک وبسایت یا یک برنامه دسکتاپی یا یک اپلیکیشن موبایل

طبق تجربه من و هم پاسخ آقای Stephen Toub به هیچ عنوان از ConfigureAwait(false) در این نوع کدها استفاده نکنید ، چون همه این کد ها دارای context می باشند که برای ردیابی وضعیت برنامه و کاربرانش استفاده می شود که در صورت استفاده از ConfigureAwait(false) ، دسترسی به این context قطع می شود ، علی الخصوص در برنامه های Server Side مثلا HttpContext.Current برابر null می شود که می تواند موجب مشکلات بسیاری برای برنامه نویس شود و در کل ریسک استفاده از ConfigureAwait(false) در برنامه های Server Side بسیار بیشتر از Client Side مثل Windows Forms و Windows Presentation Foundation (WPF) می باشد و ارزش مقداری performance بیشتر را ندارد.

1 - general-purpose library code:

اگر شما در حال توسعه یک library یا ابزار می باشید که قرار است توسط سایر برنامه نویسان مورد استفاده قرار بگیرد ، بهتر است از دستور ConfigureAwait(false) استفاده شود مثل این نمونه و این نمونه ، به طور کلی در مواردی که context ایی برای نگهداری اطلاعات کاربر و سیستم وجود ندارد , استفاده از دستور ConfigureAwait(false) توصیه شده است.