مقدمة في البرمجة غير المتزامنة في C#
البرمجة غير المتزامنة هي نموذج أساسي في التطوير الحديث باستخدام C# (.NET)، حيث تتيح إنشاء تطبيقات سريعة الاستجابة وعالية الأداء. على عكس النهج المتزامن، حيث يحجب تنفيذ الكود الخيط الحالي حتى اكتمال العملية، فإن الكود غير المتزامن يحرر الخيط لتنفيذ مهام أخرى أثناء انتظار نتيجة عملية طويلة (مثل طلب قاعدة بيانات، استدعاء HTTP، أو قراءة ملف).
مع ظهور الكلمات المفتاحية async و await في C# 5.0، أصبحت البرمجة غير المتزامنة أقل تعقيدًا وأكثر سهولة لكل مطور. في هذا الدليل، سنشرح جميع المفاهيم الأساسية: من أساسيات Task و ValueTask إلى معالجة الأخطاء وإلغاء العمليات.
أساسيات async/await و Task
ما هو Task و Task<TResult>
Task هو النوع المركزي في TPL (مكتبة المهام المتوازية)، ويمثل عملية غير متزامنة. Task (بدون قيمة إرجاع) و Task<TResult> (مع قيمة إرجاع) هما اللبنات الأساسية للكود غير المتزامن.
// طريقة غير متزامنة بسيطة بدون قيمة إرجاعpublic async Task DoSomethingAsync(){ await Task.Delay(1000); Console.WriteLine("تم!");}
// طريقة غير متزامنة مع قيمة إرجاعpublic async Task<int> CalculateSumAsync(int a, int b){ await Task.Delay(500); // محاكاة عملية طويلة return a + b;}الكلمات المفتاحية async و await
المعدل async يخبر المترجم أن الطريقة تحتوي على كود غير متزامن. العامل await يوقف تنفيذ الطريقة حتى اكتمال المهمة المنتظرة، دون حظر الخيط.
public async Task ProcessDataAsync(){ Console.WriteLine("بدء المعالجة..."); // انتظار غير متزامن — الخيط لا يُحجب string result = await FetchDataFromApiAsync(); Console.WriteLine($"تم الحصول على النتيجة: {result}");}قواعد استخدام async/await
- لا تستخدم async void (باستثناء معالجات الأحداث) — فهذا يجعل تتبع الاستثناءات مستحيلاً.
- تجنب الاستدعاءات الحاجبة (
.Result,.Wait()) — فقد تؤدي إلى حالات توقف تام (deadlock). - سمِّ الطرق غير المتزامنة باللاحقة "Async" للوضوح.
تقنيات متقدمة: ValueTask و CancellationToken والتوازي
ValueTask مقابل Task
ValueTask هو تحسين للحالات التي تكتمل فيها العملية غير المتزامنة بشكل متزامن في كثير من الأحيان (مثل البيانات المخزنة مؤقتًا). على عكس Task، وهو نوع مرجعي، فإن ValueTask هو هيكل (struct)، مما يقلل العبء على جامع القمامة (Garbage Collector).
public ValueTask<int> GetCachedOrFetchAsync(int id){ if (cache.ContainsKey(id)) { // إكمال متزامن — بدون تخصيص ذاكرة return new ValueTask<int>(cache[id]); } // إكمال غير متزامن return new ValueTask<int>(FetchFromDatabaseAsync(id));}إلغاء العمليات باستخدام CancellationToken
CancellationToken يسمح بمقاطعة العمليات غير المتزامنة الطويلة بشكل صحيح. قم دائمًا بتمرير رمز الإلغاء إذا كانت الطريقة تقبله.
public async Task<string> DownloadFileAsync(string url, CancellationToken ct){ using var client = new HttpClient(); var response = await client.GetAsync(url, ct); // ct يُمرر إلى API return await response.Content.ReadAsStringAsync();}
// الاستخدامvar cts = new CancellationTokenSource();cts.CancelAfter(TimeSpan.FromSeconds(5)); // مهلة 5 ثوانٍ
try{ string data = await DownloadFileAsync("https://example.com", cts.Tok