التزامن وتعدد الخيوط في C#: المستوى المتقدم

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

التزامن وتعدد الخيوط في C#: المستوى المتقدم

\n\n

في التطوير الحديث باستخدام C# (.NET)، تميز القدرة على إدارة التزامن وتعدد الخيوط بكفاءة المهندس المتمرس عن المبتدئ. المعرفة الأساسية بـ Thread والأقفال البسيطة لم تعد كافية لبناء تطبيقات عالية الأداء وسريعة الاستجابة وقابلة للتوسع. في هذه المقالة، سنستعرض التقنيات المتقدمة: من الفهم العميق لـ async/await إلى استخدام System.Threading.Channels و TPL Dataflow. المادة موجهة للمطورين الذين لديهم بالفعل معرفة بأساسيات تعدد الخيوط.

\n\n

1. الغوص العميق في async/await و SynchronizationContext

\n\n

يستخدم العديد من المطورين async/await، لكنهم لا يفهمون تمامًا كيف يدير جدول المهام (Task Scheduler) و SynchronizationContext الاستمراريات (continuations). على المستوى المتقدم، من المهم التحكم في أي خيط يتم تنفيذ الكود بعد await.

\n\n

بشكل افتراضي، يلتقط await SynchronizationContext الحالي (أو TaskScheduler). في تطبيقات واجهة المستخدم (WPF، WinForms)، يعيد هذا التنفيذ إلى الخيط الرئيسي. في ASP.NET Core وتطبيقات وحدة التحكم، غالبًا ما يكون السياق غائبًا، ويمكن تنفيذ الاستمرارية في أي خيط من تجمع الخيوط.

\n\n

للضبط الدقيق، استخدم ConfigureAwait(false). هذا يخبر بيئة التشغيل بعدم محاولة العودة إلى السياق الأصلي، مما يحسن الأداء ويمنع حالات الجمود (deadlocks) في كود المكتبات.

\n\n
public async Task<string> FetchDataAsync(HttpClient client)\n{\n    // لن يلتقط الاستمرارية السياق\n    var result = await client.GetStringAsync("https://api.example.com")\n                              .ConfigureAwait(false);\n    // سيتم تنفيذ هذا الكود في أي خيط من تجمع الخيوط\n    return ProcessResult(result);\n}\n\npublic async Task<string> FetchDataWithContextAsync(HttpClient client)\n{\n    // ستعود الاستمرارية إلى السياق الأصلي (مثل خيط واجهة المستخدم)\n    var result = await client.GetStringAsync("https://api.example.com");\n    // سيتم تنفيذ هذا الكود بشكل مضمون في السياق الأصلي\n    return ProcessResult(result);\n}
\n\n

نصيحة متقدمة: قم بإنشاء SynchronizationContext خاص بك للسيناريوهات غير القياسية، مثل تنظيم قائمة انتظار المهام بعدد ثابت من الخيوط.

\n\n

2. مكتبة المهام المتوازية (TPL) والتوازي في البيانات

\n\n

توفر TPL تجريدات عالية المستوى للتوازي. Parallel.For و Parallel.ForEach يقسمان المجموعات تلقائيًا إلى أجزاء (chunks) ويوزعانها على الخيوط. ومع ذلك، على المستوى المتقدم، تحتاج إلى فهم كيفية ضبط درجة التوازي ومعالجة الاستثناءات.

\n\n

استخدم ParallelOptions لتحديد عدد الخيوط، بالإضافة إلى ParallelLoopState للخروج المبكر من الحلقة.

\n\n
var options = new ParallelOptions\n{\n    MaxDegreeOfParallelism = Environment.ProcessorCount / 2 // استخدام نصف النوى\n};\n\nParallel.ForEach(sourceData, options, (item, state) =>\n{\n    try\n    {\n        // عملية ثقيلة\n        ProcessItem(item);\n    }\n    catch (Exception ex)\n    {\n        // تسجيل الخطأ وإيقاف التنفيذ\n        Console.WriteLine($"خطأ: {ex.Message}");\n        state.Stop(); // يوقف تنفيذ الحلقة\n    }\n});
\n\n

هام: Parallel.ForEach لا يضمن ترتيب المعالجة. إذا كان الترتيب مهمًا، استخدم Parallel.ForEach مع فهرس أو PLINQ (AsParallel().AsOrdered()).

\n\n

3. القنوات (System.Threading.Channels) لنمط المنتج-المستهلك

\n\n

ظهرت فئة Channel<T> في .NET Core 3.0 وأصبحت أداة قوية لسيناريوهات المنتج-المستهلك. إنها آمنة للخيوط، غير متزامنة، وفعالة. القنوات تكون

المدونات

توصيات الكتب