Estruturas de dados para programação paralela

O .NET fornece vários tipos úteis em programação paralela incluindo um conjunto de classes de coleção simultâneas, primitivas de sincronização leves e tipos para inicialização lenta. Você pode usar esses tipos com qualquer código de aplicativo multithread, incluindo PLINQ e biblioteca de paralelismo de tarefas.

Classes de coleção simultâneas

As classes de coleção no namespace System.Collections.Concurrent fornecem operações de adição e remoção thread-safe que, sempre que possível, evitam bloqueios e usam o bloqueio refinado quando os bloqueios forem necessários. Uma classe de coleção simultânea não exige que o código de usuário faça bloqueios ao acessar itens. As classes de coleção simultânea podem melhorar consideravelmente o desempenho em tipos como System.Collections.ArrayList e System.Collections.Generic.List<T> (com bloqueio implementado pelo usuário) em cenários nos quais vários threads adicionam e removem itens de uma coleção.

A tabela a seguir lista as classes de coleção simultâneas:

Tipo Descrição
System.Collections.Concurrent.BlockingCollection<T> Fornece funcionalidades de bloqueio e delimitação para coleções thread-safe que implementam System.Collections.Concurrent.IProducerConsumerCollection<T>. Os threads de produtor são bloqueados se nenhum slot estiver disponível, ou se a coleção estiver cheia. Threads de consumidor são bloqueados se a coleção estiver vazia. Esse tipo também oferece suporte ao acesso sem bloqueio de produtores e consumidores. BlockingCollection<T> pode ser usado como uma classe base ou repositório de backup para fornecer bloqueio e limitação a qualquer classe de coleção que ofereça suporte a IEnumerable<T>.
System.Collections.Concurrent.ConcurrentBag<T> Uma implementação de recipiente thread-safe que fornece operações de adição e get escalonáveis.
System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> Um tipo de dicionário simultâneo e escalonável.
System.Collections.Concurrent.ConcurrentQueue<T> Uma fila FIFO simultânea e escalonável.
System.Collections.Concurrent.ConcurrentStack<T> Uma pilha LIFO simultânea e escalonável.

Para obter mais informações, veja Coleções thread-safe.

Primitivos de sincronização

Os primitivos de sincronização no namespace System.Threading habilitam a simultaneidade refinada e o desempenho mais rápido, evitando mecanismos de bloqueio caros encontrados no código de multithreading herdado.

A tabela a seguir lista os tipos de sincronização:

Tipo Descrição
System.Threading.Barrier Permite que vários threads funcionem em um algoritmo em paralelo fornecendo um ponto em que cada tarefa pode sinalizar sua chegada e, depois, gerar um bloqueio até que algumas ou todas as tarefas tenham chegado. Para saber mais, consulte Barreira.
System.Threading.CountdownEvent Simplifica cenários de bifurcação e junção fornecendo um mecanismo fácil de encontro. Para saber mais, confira CountdownEvent.
System.Threading.ManualResetEventSlim Um primitivo de sincronização semelhante a System.Threading.ManualResetEvent. ManualResetEventSlim é leve, mas só pode ser usado para comunicação entre processos.
System.Threading.SemaphoreSlim Um primitivo de sincronização que limita o número de threads que podem acessar simultaneamente um recurso ou um pool de recursos. Para saber mais, confira Semaphore e SemaphoreSlim.
System.Threading.SpinLock Um primitivo de bloqueio de exclusão mútua que faz com que o thread que está tentando adquirir o bloqueio aguarde em um loop, ou rotação, durante um período antes de gerar seu quantum. Em cenários nos quais a espera pelo bloqueio deve ser curta, SpinLock oferece um desempenho melhor do que outras formas de bloqueio. Para saber mais, veja SpinLock.
System.Threading.SpinWait Um tipo de pequeno e leve que girará por um tempo especificado e, no final, colocará o thread em um estado de espera se a contagem de rotações for ultrapassada. Para saber mais, veja SpinWait.

Para obter mais informações, consulte:

Classes de inicialização lenta

Com a inicialização lenta, a memória de um objeto não é alocada até que seja necessário. A inicialização lenta pode melhorar o desempenho distribuindo as alocações de objeto uniformemente entre o tempo de vida de um programa. Você pode habilitar a inicialização lenta para qualquer tipo personalizado encapsulando o tipo Lazy<T>.

A tabela a seguir lista os tipos de inicialização lenta:

Tipo Descrição
System.Lazy<T> Fornece inicialização lenta, leve e thread-safe.
System.Threading.ThreadLocal<T> Fornece um valor com inicialização lenta em uma base por thread, com cada thread invocando lentamente a função de inicialização.
System.Threading.LazyInitializer Fornece métodos estáticos que evitam a necessidade de alocar uma instância dedicada de inicialização lenta. Em vez disso, usam referências para garantir que os destinos sejam inicializados conforme são acessados.

Para obter mais informações, veja Inicialização lenta.

Agregar exceções

O tipo System.AggregateException pode ser usado para capturar várias exceções lançadas simultaneamente em threads separados e retorná-las para o thread associado como uma única exceção. Os tipos System.Threading.Tasks.Task e System.Threading.Tasks.Parallel e o PLINQ usam AggregateException extensivamente para essa finalidade. Para saber mais, veja Tratamento de exceções e Como tratar exceções em uma consulta PLINQ.

Confira também