Compartilhar via


Coleções thread-safe

O System.Collections.Concurrent namespace inclui várias classes de coleção que são thread-safe e escalonáveis. Vários threads podem adicionar ou remover itens com segurança e eficiência dessas coleções, sem a necessidade de sincronização adicional no código do usuário. Ao escrever um novo código, use as classes de coleção simultâneas para gravar vários threads na coleção simultaneamente. Se você estiver apenas lendo uma coleção compartilhada, use as classes no namespace System.Collections.Generic.

System.Collections e System.Collections.Generic

As classes de coleção no System.Collections namespace incluem ArrayList e Hashtable. Essas classes fornecem certa segurança de thread por meio da propriedade Synchronized, que retorna um encapsulamento thread-safe em torno da coleção. O wrapper funciona bloqueando toda a coleção em cada operação de adição ou remoção. Portanto, cada thread que está tentando acessar a coleção deve aguardar por sua vez para receber esse bloqueio. Esse processo não é escalonável e pode causar degradação significativa de desempenho para grandes coleções. Além disso, o design não está protegido contra condições de corrida. Para obter mais informações, consulte Sincronização em Coleções Genéricas.

As classes de coleção no System.Collections.Generic namespace incluem List<T> e Dictionary<TKey,TValue>. Essas classes fornecem melhor segurança de tipo e desempenho em comparação com as System.Collections classes. No entanto, as System.Collections.Generic classes não fornecem nenhuma sincronização de thread; o código do usuário deve fornecer toda a sincronização quando os itens são adicionados ou removidos em vários threads simultaneamente.

É recomendável usar as classes de coleções simultâneas no System.Collections.Concurrent namespace, pois elas fornecem segurança de tipo e também segurança de thread mais eficiente e completa.

Bloqueio refinado e mecanismos sem bloqueio

Alguns dos tipos de coleção simultânea usam mecanismos de sincronização leve, como SpinLock, SpinWaite SemaphoreSlimCountdownEvent. Esses tipos de sincronização geralmente usam rotação ocupada por breves períodos antes de colocarem o thread em um verdadeiro estado Wait. Quando espera-se que os tempos de espera sejam curtos, girar é muito menos dispendioso em termos de recursos computacionais do que esperar, o que envolve uma transição de kernel que utiliza muitos recursos. Para classes de coleção que usam o giro, essa eficiência significa que vários threads podem adicionar e remover itens em uma taxa alta. Para saber mais sobre rotação versus bloqueio, consulte SpinLock e SpinWait.

As classes ConcurrentQueue<T> e ConcurrentStack<T> não usam bloqueios. Em vez disso, elas usam operações do Interlocked para obter acesso thread-safe.

Observação

Como as classes de coleções simultâneas dão suporte a ICollection, elas fornecem implementações para as propriedades IsSynchronized e SyncRoot, embora essas propriedades sejam irrelevantes. IsSynchronized sempre retorna false e é SyncRoot sempre null (Nothing no Visual Basic).

A tabela a seguir lista os tipos de coleção no System.Collections.Concurrent namespace:

Tipo Descrição
BlockingCollection<T> Fornece funcionalidade de delimitação e bloqueio de qualquer tipo que implemente IProducerConsumerCollection<T>. Para obter mais informações, consulte Visão geral de BlockingCollection.
ConcurrentDictionary<TKey,TValue> Implementação thread-safe de um dicionário de pares chave-valor.
ConcurrentQueue<T> Implementação thread-safe de uma fila PEPS (primeiro a entrar, primeiro a sair).
ConcurrentStack<T> Implementação thread-safe de uma fila LIFO (último a entrar, primeiro a sair).
ConcurrentBag<T> Implementação thread-safe de uma coleção não ordenada de elementos.
IProducerConsumerCollection<T> A interface que um tipo deve implementar para uso em um BlockingCollection.
Título Descrição
Visão geral de BlockingCollection Descreve a funcionalidade fornecida pelo BlockingCollection<T> tipo.
Como adicionar e remover itens de um ConcurrentDictionary Descreve como adicionar e remover elementos de um ConcurrentDictionary<TKey,TValue>
Como fazer: Adicionar e remover itens individualmente de um BlockingCollection Descreve como adicionar e recuperar itens de uma coleta de bloqueio sem usar o enumerador de somente leitura.
Como adicionar funcionalidade delimitadora e de bloqueio a uma coleção Descreve como usar qualquer classe de coleção como o mecanismo de armazenamento subjacente para uma IProducerConsumerCollection<T> coleção.
Como: Usar ForEach para remover itens em uma BlockingCollection Descreve como usar foreach (For Each no Visual Basic) para remover todos os itens em uma coleção de bloqueios.
Como usar matrizes de coleções de bloqueio em um pipeline Descreve como usar várias coleções de bloqueio ao mesmo tempo para implementar um pipeline.
Como criar um pool de objetos usando um ConcurrentBag Mostra como usar uma bolsa concorrente para melhorar a performance em cenários em que você pode reutilizar objetos em vez de criar continuamente novos.

Referência