Trabalhando com filas de tarefas em C#: guia completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course
```html

Introdução às filas de tarefas em C#



Na programação multithread moderna, a fila de tarefas (task queue) é um padrão fundamental para organizar o processamento assíncrono de dados. Em C# (.NET), esse padrão é implementado através de vários mecanismos poderosos que permitem aos desenvolvedores gerenciar eficientemente os fluxos de execução e distribuir a carga.



A fila de tarefas resolve o problema clássico de producer-consumer (produtor-consumidor), onde uma parte do código cria tarefas e a outra as processa. Neste artigo, vamos explorar as principais formas de implementar filas de tarefas em C#: desde coleções simples até canais modernos (Channel).



Principais abordagens para implementar filas de tarefas



1. ConcurrentQueue — Fila thread-safe



A implementação mais simples e de baixo nível é ConcurrentQueue<T> do namespace System.Collections.Concurrent. Ela fornece os métodos thread-safe Enqueue e TryDequeue.



using System;using System.Collections.Concurrent;using System.Threading.Tasks;

public class SimpleTaskQueue{ private readonly ConcurrentQueue<Action> _tasks = new(); private readonly Task _worker;

public SimpleTaskQueue() { _worker = Task.Run(ProcessTasks); }

public void Enqueue(Action task) { _tasks.Enqueue(task); }

private void ProcessTasks() { while (true) { if (_tasks.TryDequeue(out var task)) { task(); } } }}


Vantagens:

  • Simplicidade de uso
  • Baixo consumo de memória
  • Thread-safe sem bloqueios


Desvantagens:

  • Espera ativa (busy waiting) no loop
  • Ausência de sinalização sobre novas tarefas
  • Dificuldade para parar


2. BlockingCollection — Fila com bloqueio



BlockingCollection<T> resolve o problema da espera ativa. Ela fornece os métodos Add e Take, que bloqueiam a thread até que os dados estejam disponíveis.



using System;using System.Collections.Concurrent;using System.Threading.Tasks;

public class BlockingTaskQueue : IDisposable{ private readonly BlockingCollection<Action> _tasks = new(new ConcurrentQueue<Action>()); private readonly Task[] _workers; private bool _disposed;

public BlockingTaskQueue(int workerCount = 4) { _workers = new Task[workerCount]; for (int i = 0; i < workerCount; i++) { _workers[i] = Task.Run(ProcessTasks); } }

public void Enqueue(Action task) { _tasks.Add(task); }

private void ProcessTasks() { foreach (var task in _tasks.GetConsumingEnumerable()) { if (_disposed) break; task(); } }

public void CompleteAdding() { _tasks.CompleteAdding(); }

public void Dispose() { _disposed = true; _tasks.CompleteAdding(); Task.WaitAll(_workers); _tasks.Dispose(); }}


Características principais:

  • Bloqueio automático da thread quando não há tarefas
  • Suporte a cancelamento via CancellationToken
  • Possibilidade de limitar a capacidade da fila
  • Finalização segura através de CompleteAdding


Abordagem moderna: Channel<T>



A partir do .NET Core 3.0 e .NET 5, o C# introduziu System.Threading.Channels.Channel<T> — esta é a implementação mais performática e flexível de fila de tarefas. Ela suporta operações assíncronas, cancelamento e limitação de throughput. ```

Blogs

Book Recommendations