Producteur/consommateur avec Channels (vue d’ensemble)
Modélisez des files producteur/consommateur comme Channels avec BlockingCollection : tampons de taille limitée (contre-pression), plusieurs consommateurs et achèvement progressif.
Producteur/consommateur avec Channels (vue d’ensemble) est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 3. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 3 leçons au total.
Concepts et objectifs
Objectif : créer une chaîne de traitement producteur-consommateur sûre.
- Idée du canal : une file d’attente entre les producteurs et les consommateurs
- Une capacité bornée fournit une contre-pression
- Prendre en charge plusieurs consommateurs
- Utiliser CompleteAdding pour un arrêt propre
Un producteur et un consommateur
Flux de base : les producteurs utilisent Add, les consommateurs parcourent GetConsumingEnumerable, puis CompleteAdding termine le traitement.
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);
}
}
Démonstration de la contre-pression
Les files d’attente bornées appliquent une contre-pression : lorsqu’elles sont pleines, Add se bloque jusqu’à ce que les consommateurs libèrent de l’espace.
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);
}
}
Distribution entre consommateurs
Plusieurs consommateurs se disputent les éléments (distribution). Le travail est automatiquement réparti entre les threads.
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());
}
}
Achèvement propre
Utilisez CompleteAdding et GetConsumingEnumerable pour terminer proprement lorsque la file d’attente est vide.
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);
}
}
Conseils et pièges
Conseils :
- Préférez les tampons bornés pour empêcher la croissance de la mémoire.
- Utilisez GetConsumingEnumerable pour éviter les problèmes de concurrence lors de l’achèvement.
- Gardez les éléments de travail petits et indépendants ; évitez l’état partagé.
- Journalisez et gérez les erreurs dans les consommateurs pour éviter les arrêts silencieux.
Rôle de CompleteAdding
Récapitulatif
Récapitulatif : utilisez une BlockingCollection bornée pour simuler des canaux, répartissez le travail entre plusieurs consommateurs et utilisez CompleteAdding pour un arrêt progressif.
Questions Fréquemment Posées
La leçon « Producteur/consommateur avec Channels (vue d’ensemble) » est-elle gratuite ?
Oui — le texte complet de « Producteur/consommateur avec Channels (vue d’ensemble) » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 3 leçons au total.
Qu'est-ce que j'apprendrai dans « Producteur/consommateur avec Channels (vue d’ensemble) » ?
Modélisez des files producteur/consommateur comme Channels avec BlockingCollection : tampons de taille limitée (contre-pression), plusieurs consommateurs et achèvement progressif. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer C# Academy ?
Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 3.
Combien de temps prend la leçon « Producteur/consommateur avec Channels (vue d’ensemble) » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?
Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Parallel.ForEach et PLINQ
- Producteur/consommateur avec Channels (vue d’ensemble)
- Compromis entre débit et latence