Producer/Consumer mit Channels (Überblick)
Modellieren Sie Producer-/Consumer-Warteschlangen wie Channels mit BlockingCollection : begrenzte Puffer (Backpressure), mehrere Consumer und ein ordnungsgemäßer Abschluss.
Producer/Consumer mit Channels (Überblick) ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 3. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 3 Lektionen.
Konzept und Ziele
Ziel: Erstellen Sie eine sichere Produzenten-/Konsumentenpipeline.
- Channel-Idee: eine Warteschlange zwischen Produzenten und Konsumenten
- Begrenzte Kapazität sorgt für Backpressure
- Unterstützung für mehrere Konsumenten
- Verwenden Sie CompleteAdding für ein sauberes Herunterfahren
Ein Produzent/ein Konsument
Grundablauf: Produzenten rufen Add auf, Konsumenten durchlaufen GetConsumingEnumerable; anschließend rufen Sie CompleteAdding zum Beenden auf.
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);
}
}
Backpressure-Demo
Begrenzte Warteschlangen erzeugen Backpressure: Wenn sie voll sind, blockiert Add, bis Konsumenten Platz schaffen.
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);
}
}
Konsumenten mit Fan-out
Mehrere Konsumenten konkurrieren um Elemente (Fan-out). Die Arbeit wird automatisch auf Threads verteilt.
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());
}
}
Sauberer Abschluss
Verwenden Sie CompleteAdding und GetConsumingEnumerable, um die Verarbeitung sauber zu beenden, sobald die Warteschlange leer ist.
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);
}
}
Tipps und Fallstricke
Tipps:
- Bevorzugen Sie begrenzte Puffer, um Speicherwachstum zu verhindern.
- Verwenden Sie GetConsumingEnumerable, um Race Conditions beim Abschluss zu vermeiden.
- Halten Sie Arbeitselemente klein und unabhängig; vermeiden Sie gemeinsam genutzten Zustand.
- Protokollieren und behandeln Sie Fehler innerhalb der Konsumenten, um unbemerkte Abbrüche zu vermeiden.
Zweck von CompleteAdding
Zusammenfassung
Zusammenfassung: Verwenden Sie eine begrenzte BlockingCollection, um Kanäle nachzubilden, verteilen Sie die Arbeit auf mehrere Konsumenten und verwenden Sie CompleteAdding für ein geordnetes Herunterfahren.
Häufig gestellte Fragen
Ist die Lektion „Producer/Consumer mit Channels (Überblick)“ kostenlos?
Ja — der vollständige Text von „Producer/Consumer mit Channels (Überblick)“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 3 Lektionen.
Was lerne ich in „Producer/Consumer mit Channels (Überblick)“?
Modellieren Sie Producer-/Consumer-Warteschlangen wie Channels mit BlockingCollection : begrenzte Puffer (Backpressure), mehrere Consumer und ein ordnungsgemäßer Abschluss. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um C# Academy zu starten?
Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 3.
Wie lange dauert die Lektion „Producer/Consumer mit Channels (Überblick)“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?
Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Parallel.ForEach, PLINQ
- Producer/Consumer mit Channels (Überblick)
- Abwägung zwischen Durchsatz und Latenz