التزامن وتعدد الخيوط في C#: المستوى المتقدم
في التطوير الحديث باستخدام C#، التزامن وتعدد الخيوط ليسا مجرد توسيع للإمكانيات، بل أدوات أساسية لإنشاء تطبيقات سريعة وسريعة الاستجابة وقابلة للتوسع. على المستوى المتقدم، نتجاوز مجرد تشغيل Task.Run ونواجه تفاصيل المجدولين، ومزامنة السياقات، والأنماط للعمل مع البيانات المشتركة. في هذه المقالة، سنستعرض المفاهيم المتقدمة الرئيسية للتزامن في C# (.NET) التي ستساعدك على كتابة كود فعال وآمن.
1. Task و ValueTask: استخدام متعمق
الفئة Task هي أساس البرمجة غير المتزامنة في C#. ومع ذلك، على المستوى المتقدم، من المهم فهم الفرق بين Task و ValueTask، بالإضافة إلى إدارة دورة حياة المهام.
متى نستخدم ValueTask؟
ValueTask هي بنية تسمح بتجنب تخصيص الذاكرة لكائن Task عندما تكون النتيجة متاحة بشكل متزامن. هذا أمر بالغ الأهمية لسيناريوهات الأداء العالي، مثل طرق التخزين المؤقت.
public class CacheService{ private readonly Dictionary<string, string> _cache = new();
public async ValueTask<string> GetDataAsync(string key) { if (_cache.TryGetValue(key, out string value)) { // النتيجة موجودة بالفعل، لا نقوم بإنشاء Task return value; }
// الحصول على البيانات بشكل غير متزامن string data = await FetchFromDatabaseAsync(key); _cache[key] = data; return data; }
private async Task<string> FetchFromDatabaseAsync(string key) { await Task.Delay(100); // محاكاة تأخير return $"Data for {key}"; }}معالجة الأخطاء والإلغاء المتقدمة
استخدم CancellationToken لإلغاء العمليات الطويلة بشكل صحيح. قم بدمج عدة رموز مميزة عبر CancellationTokenSource.CreateLinkedTokenSource.
public async Task ProcessWithTimeoutAsync(CancellationToken externalToken){ using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(externalToken, timeoutCts.Token);
try { await LongRunningOperationAsync(linkedCts.Token); } catch (OperationCanceledException) { Console.WriteLine("تم إلغاء العملية أو تجاوز المهلة."); }}2. SynchronizationContext ومجدولو المهام
فهم SynchronizationContext ضروري للعمل مع خيوط واجهة المستخدم (WPF، WinForms) و ASP.NET Core. على المستوى المتقدم، يمكنك إنشاء سياقات مزامنة خاصة بك.
تكوين السياق لمجموعة الخيوط
بشكل افتراضي، يلتقط await SynchronizationContext الحالي. لتجنب ذلك (ومنع deadlock)، استخدم ConfigureAwait(false).
public async Task ProcessDataAsync(){ // يتم تنفيذ هذا الكود في السياق الأصلي (مثل واجهة المستخدم) await Task.Run(() => HeavyComputation()).ConfigureAwait(false);
// بعد ConfigureAwait(false) — في سياق مجموعة الخيوط // لا يوجد وصول لعناصر واجهة المستخدم! Console.WriteLine("تم التنفيذ في خيط من المجموعة");}إنشاء مجدول مخصص
يمكنك تنفيذ TaskScheduler الخاص بك، على سبيل المثال، للحد من عدد المهام المنفذة في وقت واحد (مشابه لـ SemaphoreSlim على مستوى المجدول).
public class LimitedConcurrencyTaskScheduler : TaskScheduler{ private readonly SemaphoreSlim _semaphore; private int _runningTasks;
public LimitedConcurrencyTaskScheduler(int maxConcurrency) { _semaphore = new SemaphoreSlim(maxConcurrency);