0Pricing
C# Academy · Aula

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

Verificação rápida: O que chamar CompleteAdding() em uma BlockingCollection faz?

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

  1. Parallel.ForEach, PLINQ
  2. Produtor/consumidor com Channels (visão geral)
  3. Compromissos entre vazão e latência
← Voltar para C# Academy