Produtor/consumidor com Channels (visão geral)
Modele filas de produtor/consumidor semelhantes a Channels usando BlockingCollection : buffers limitados (contrapressão), vários consumidores e conclusão elegante.
Produtor/consumidor com Channels (visão geral) é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 3. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 3 aulas no total.
Conceito e objetivos
Objetivo: Criar um fluxo seguro de produtor e consumidor.
- Ideia de canal: uma queue entre produtores e consumidores
- A capacidade limitada fornece contrapressão
- Ofereça suporte a vários consumidores
- Use CompleteAdding para um encerramento limpo
Um produtor e um consumidor
Fluxo básico: os produtores usam Add, os consumidores iteram sobre GetConsumingEnumerable e, em seguida, usam CompleteAdding para concluir.
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);
}
}
Demonstração de contrapressão
As filas limitadas aplicam contrapressão: quando estão cheias, Add bloqueia até que os consumidores liberem espaço.
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);
}
}
Distribuição entre consumidores
Vários consumidores competem pelos itens (distribuição). O trabalho é compartilhado automaticamente entre as 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());
}
}
Conclusão limpa
Use CompleteAdding e GetConsumingEnumerable para concluir de forma limpa quando a fila for esvaziada.
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);
}
}
Dicas e armadilhas
Dicas:
- Prefira buffers limitados para evitar o crescimento da memória.
- Use GetConsumingEnumerable para evitar condições de corrida na conclusão.
- Mantenha os itens de trabalho pequenos e independentes; evite estado compartilhado.
- Registre e trate os erros dentro dos consumidores para evitar interrupções silenciosas.
Objetivo de CompleteAdding
Resumo
Resumo: Use uma BlockingCollection limitada para simular canais, distribua o trabalho entre vários consumidores e use CompleteAdding para um encerramento normal.
Perguntas Frequentes
A aula “Produtor/consumidor com Channels (visão geral)” é grátis?
Sim — o texto completo de “Produtor/consumidor com Channels (visão geral)” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 3 aulas no total.
O que vou aprender em “Produtor/consumidor com Channels (visão geral)”?
Modele filas de produtor/consumidor semelhantes a Channels usando BlockingCollection : buffers limitados (contrapressão), vários consumidores e conclusão elegante. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 3.
Quanto tempo leva a aula “Produtor/consumidor com Channels (visão geral)”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Parallel.ForEach, PLINQ
- Produtor/consumidor com Channels (visão geral)
- Compromissos entre vazão e latência