المنتِج/المستهلك باستخدام Channels (نظرة عامة)
نمذج قوائم انتظار المنتج/المستهلك مثل Channels باستخدام BlockingCollection : مخازن محدودة (الضغط العكسي)، ومستهلكون متعددون، وإكمال سلس.
المنتِج/المستهلك باستخدام Channels (نظرة عامة) درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 2 من أصل 3. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 3 دروس في المجموع.
المفهوم والأهداف
الهدف: بناء مسار آمن للمنتج والمستهلك.
- فكرة القناة: قائمة انتظار بين المنتجين والمستهلكين
- توفر السعة المحدودة ضغطًا عكسيًا
- دعم مستهلكين متعددين
- استخدام CompleteAdding للإيقاف السليم
منتج ومستهلك واحد
التدفق الأساسي: يضيف المنتجون العناصر باستخدام Add، ويكرّر المستهلكون عبر GetConsumingEnumerable، ثم يُستدعى CompleteAdding لإنهاء التدفق.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
// Unbounded by default; simple demo
BlockingCollection<int> queue = new BlockingCollection<int>();
// Producer
Task producer = Task.Run(() =>
{
for (int i = 1; i <= 5; i++)
{
queue.Add(i); // enqueue
Console.WriteLine("Produced " + i);
Thread.Sleep(50); // simulate work
}
queue.CompleteAdding(); // signal no more items
});
// Consumer
Task consumer = Task.Run(() =>
{
foreach (int x in queue.GetConsumingEnumerable())
{
Console.WriteLine("Consumed " + x);
Thread.Sleep(80); // simulate processing
}
Console.WriteLine("Consumer done");
});
Task.WaitAll(producer, consumer);
}
}
مثال على الضغط العكسي
تطبّق قوائم الانتظار المحدودة ضغطًا عكسيًا: فعندما تمتلئ، تحظر Add التنفيذ حتى يوفّر المستهلكون مساحة.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
// Bounded capacity introduces backpressure
BlockingCollection<int> queue = new BlockingCollection<int>(boundedCapacity: 2);
Task producer = Task.Run(() =>
{
for (int i = 1; i <= 5; i++)
{
queue.Add(i); // blocks when the buffer is full
Console.WriteLine("Produced " + i + " (count=" + queue.Count + ")");
}
queue.CompleteAdding();
});
Task consumer = Task.Run(() =>
{
foreach (int x in queue.GetConsumingEnumerable())
{
Console.WriteLine("Consumed " + x);
Thread.Sleep(120); // slower consumer -> producer will block sometimes
}
});
Task.WaitAll(producer, consumer);
}
}
توزيع العمل على المستهلكين
يتنافس المستهلكون المتعددون على العناصر، في عملية توزيع للعمل (fan-out). ويتوزع العمل تلقائيًا عبر خيوط التنفيذ.
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
BlockingCollection<int> queue = new BlockingCollection<int>(3);
Task prod = Task.Run(() =>
{
for (int i = 1; i <= 8; i++)
{
queue.Add(i);
Console.WriteLine("Produced " + i);
Thread.Sleep(30);
}
queue.CompleteAdding();
});
// Start 2 consumers that compete for items
Task[] consumers = Enumerable.Range(1, 2).Select(id => Task.Run(() =>
{
foreach (int x in queue.GetConsumingEnumerable())
{
Console.WriteLine("C" + id + " got " + x);
Thread.Sleep(100);
}
Console.WriteLine("C" + id + " done");
})).ToArray();
Task.WaitAll(consumers.Concat(new[] { prod }).ToArray());
}
}
الإكمال السليم
استخدم CompleteAdding وGetConsumingEnumerable للإنهاء بطريقة سليمة عند إفراغ قائمة الانتظار.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
static void Producer(BlockingCollection<string> q)
{
string[] lines = { "A", "B", "C", "D" };
foreach (var s in lines)
{
q.Add(s);
Console.WriteLine("Produced " + s);
}
q.CompleteAdding(); // signal completion
}
static void Consumer(BlockingCollection<string> q)
{
try
{
foreach (var item in q.GetConsumingEnumerable())
{
Console.WriteLine("Consumed " + item);
Thread.Sleep(60);
}
Console.WriteLine("Consumer finished all items");
}
catch (InvalidOperationException)
{
// Thrown if taken after completion and empty; avoided by foreach above.
}
}
public static void Main(string[] args)
{
var queue = new BlockingCollection<string>(2);
Task p = Task.Run(() => Producer(queue));
Task c = Task.Run(() => Consumer(queue));
Task.WaitAll(p, c);
}
}
النصائح والمزالق
نصائح:
- فضّل المخازن المحدودة لمنع نمو الذاكرة.
- استخدم GetConsumingEnumerable لتجنب حالات السباق عند الإكمال.
- حافظ على صغر عناصر العمل واستقلالها؛ وتجنب الحالة المشتركة.
- سجّل الأخطاء وعالجها داخل المستهلكين لتجنب التوقفات الصامتة.
الغرض من CompleteAdding
مراجعة
مراجعة: استخدم BlockingCollection محدودة لمحاكاة القنوات، ووزّع العمل على مستهلكين متعددين، واستخدم CompleteAdding للإيقاف السلس.
الأسئلة الشائعة
هل درس «المنتِج/المستهلك باستخدام Channels (نظرة عامة)» مجاني؟
نعم — نص درس «المنتِج/المستهلك باستخدام Channels (نظرة عامة)» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 3 دروس في المجموع.
ماذا ستتعلم في «المنتِج/المستهلك باستخدام Channels (نظرة عامة)»؟
نمذج قوائم انتظار المنتج/المستهلك مثل Channels باستخدام BlockingCollection : مخازن محدودة (الضغط العكسي)، ومستهلكون متعددون، وإكمال سلس. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 3.
كم من الوقت يستغرق درس «المنتِج/المستهلك باستخدام Channels (نظرة عامة)»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- Parallel.ForEach وPLINQ
- المنتِج/المستهلك باستخدام Channels (نظرة عامة)
- المفاضلة بين الإنتاجية وزمن الاستجابة