برنامهنویسی ناهمگام با async و await
برنامهنویسی ناهمگام با async و await
بخشی از آموزش جامع C# و .NET 10
محتوای درس برنامهنویسی ناهمگام با async و await
Async Programming برای عملیات I/O مانند فایل، شبکه و پایگاه داده از Block شدن Thread جلوگیری میکند. async و await کد ناهمگام را با ساختار خوانا و قابل مدیریت ارائه میکنند.
۱. Task و Task<T>
Task نماینده عملیات در حال اجرا یا آینده است و Task<T> نتیجهای از نوع T تولید میکند.
مثال
static async Task<int> Load()=>{await Task.Delay(50);return 42;}
Console.WriteLine(await Load());در این مثال، مفهوم «Task و Task<T>» در یک قطعه کد مستقل نمایش داده شده است. مقدارها و نامها عمداً ساده انتخاب شدهاند تا رفتار اصلی قابل مشاهده باشد؛ در پروژه واقعی همین الگو با مدل دامنه، اعتبارسنجی و مدیریت خطای متناسب ترکیب میشود.
۲. async و await
async امکان استفاده از await را فراهم میکند و await ادامه متد را پس از تکمیل Task زمانبندی میکند.
مثال
await Task.Delay(50); Console.WriteLine("Done");در این مثال، مفهوم «async و await» در یک قطعه کد مستقل نمایش داده شده است. مقدارها و نامها عمداً ساده انتخاب شدهاند تا رفتار اصلی قابل مشاهده باشد؛ در پروژه واقعی همین الگو با مدل دامنه، اعتبارسنجی و مدیریت خطای متناسب ترکیب میشود.
۳. I/O-bound و CPU-bound
async برای I/O-bound بسیار مؤثر است. برای CPU-bound ممکن است Parallelism یا Task.Run در لایه مناسب مطرح شود.
مثال
string text=await File.ReadAllTextAsync("data.txt");در این مثال، مفهوم «I/O-bound و CPU-bound» در یک قطعه کد مستقل نمایش داده شده است. مقدارها و نامها عمداً ساده انتخاب شدهاند تا رفتار اصلی قابل مشاهده باشد؛ در پروژه واقعی همین الگو با مدل دامنه، اعتبارسنجی و مدیریت خطای متناسب ترکیب میشود.
۴. Exception
Exceptionهای Task هنگام await مانند کد همگام قابل مدیریتاند.
مثال
try
{
await Task.Delay(50);
throw new InvalidOperationException("Async failure");
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.Message);
}در این مثال، مفهوم «Exception» در یک قطعه کد مستقل نمایش داده شده است. مقدارها و نامها عمداً ساده انتخاب شدهاند تا رفتار اصلی قابل مشاهده باشد؛ در پروژه واقعی همین الگو با مدل دامنه، اعتبارسنجی و مدیریت خطای متناسب ترکیب میشود.
۵. CancellationToken
عملیات طولانی یا I/O بهتر است در صورت امکان Cancellation را بپذیرند تا فراخواننده کنترل Lifecycle داشته باشد.
مثال
using var cts=new CancellationTokenSource(100);
try{await Task.Delay(1000,cts.Token);}catch(OperationCanceledException){}در این مثال، مفهوم «CancellationToken» در یک قطعه کد مستقل نمایش داده شده است. مقدارها و نامها عمداً ساده انتخاب شدهاند تا رفتار اصلی قابل مشاهده باشد؛ در پروژه واقعی همین الگو با مدل دامنه، اعتبارسنجی و مدیریت خطای متناسب ترکیب میشود.
۶. ConfigureAwait
در بسیاری از Applicationهای مدرن نیاز مستقیم کمی دارد، اما مفهوم Context برای کتابخانهها و UIها مهم است.
مثال
await Task.Delay(10).ConfigureAwait(false);در این مثال، مفهوم «ConfigureAwait» در یک قطعه کد مستقل نمایش داده شده است. مقدارها و نامها عمداً ساده انتخاب شدهاند تا رفتار اصلی قابل مشاهده باشد؛ در پروژه واقعی همین الگو با مدل دامنه، اعتبارسنجی و مدیریت خطای متناسب ترکیب میشود.
۷. مثالهای عملی
static async Task<string> LoadAsync(string path, CancellationToken ct)
{
return await File.ReadAllTextAsync(path, ct);
}این نمونه عملی چند مفهوم فصل را در کنار هم قرار میدهد و برای مشاهده رفتار واقعی کد قابل اجرا و تغییر است.
Task<string> a = File.ReadAllTextAsync("a.txt");
Task<string> b = File.ReadAllTextAsync("b.txt");
string[] results = await Task.WhenAll(a, b);این نمونه عملی چند مفهوم فصل را در کنار هم قرار میدهد و برای مشاهده رفتار واقعی کد قابل اجرا و تغییر است.
۸. خطاهای رایج
• استفاده از .Result یا .Wait بدون دلیل
• async void بهجز Event Handler
• نادیده گرفتن Cancellation در عملیات طولانی
۹. نکات اجرایی
• نامها، Typeها و Methodها را متناسب با مفهوم دامنه و بدون ابهام انتخاب کنید.
• هشدارهای کامپایلر و Nullable را بدون بررسی خاموش نکنید.
• منطق هر بخش را تا حد امکان کوچک، قابل تست و مستقل از I/O غیرضروری نگه دارید.
۱۰. تمرین عملی
برنامهای بسازید که چند فایل را بهصورت همزمان با Task.WhenAll بخواند و مجموع تعداد کاراکترها را نمایش دهد.
۱۱. جمعبندی
در این فصل، مبانی «برنامهنویسی ناهمگام با async و await» با تمرکز بر ساختارهای اصلی زبان، الگوهای صحیح استفاده و خطاهای رایج بررسی شد. تسلط بر این مفاهیم زمینه لازم برای اتصال موضوع به فصلهای بعدی و طراحی کدهای خواناتر، قابل نگهداری و قابل تست را فراهم میکند.