Partager via


Collections thread-safe

L’espace System.Collections.Concurrent de noms comprend plusieurs classes de collection qui sont à la fois thread-safe et scalables. Plusieurs threads peuvent ajouter ou supprimer efficacement des éléments de ces collections sans nécessiter de synchronisation supplémentaire dans le code utilisateur. Lorsque vous écrivez du nouveau code, utilisez les classes de collection simultanées pour écrire plusieurs threads dans la collection simultanément. Si vous lisez uniquement à partir d'une collection partagée, vous pouvez utiliser les classes de l'espace de noms System.Collections.Generic.

System.Collections et System.Collections.Generic

Les classes de collection de l’espace de nom System.Collections incluent ArrayList et Hashtable. Ces classes fournissent une sécurité de thread via la propriété Synchronized qui retourne un wrapper thread-safe autour de la collection. Le wrapper fonctionne en verrouillant l’intégralité de la collection sur chaque opération d’ajout ou de suppression. Par conséquent, chaque thread qui tente d’accéder à la collection doit attendre son tour pour prendre le verrou. Ce processus n’est pas évolutif et peut entraîner une dégradation significative des performances pour les grandes collections. En outre, la conception n’est pas protégée contre les conditions de course. Pour plus d’informations, consultez Synchronisation dans les collections génériques.

Les classes de collection de l’espace de nom System.Collections.Generic incluent List<T> et Dictionary<TKey,TValue>. Ces classes offrent une sécurité et des performances de type améliorées par rapport aux System.Collections classes. Toutefois, les System.Collections.Generic classes ne fournissent aucune synchronisation de threads ; le code utilisateur doit fournir toutes les synchronisations lorsque des éléments sont ajoutés ou supprimés simultanément sur plusieurs threads.

Nous vous recommandons d’utiliser les classes de regroupements simultanées dans l’espace System.Collections.Concurrent de noms, car elles fournissent une sécurité de type et une sécurité de thread plus efficace et complète.

Verrouillage de granularité fine et mécanismes sans verrou

Certains des types de collection simultanés utilisent des mécanismes de synchronisation légers tels que SpinLock, , SpinWaitSemaphoreSlim, et CountdownEvent. Ces types de synchronisation utilisent généralement la rotation intensive pendant de courtes périodes avant de mettre le thread dans un véritable état Wait. Lorsque les temps d’attente sont supposés être courts, la rotation est beaucoup moins gourmande en ressources informatiques que l’attente, qui implique une transition de noyau coûteuse. Pour les classes de collections qui utilisent la rotation, cette efficacité signifie que plusieurs threads peuvent ajouter et supprimer des éléments à un taux très élevé. Pour plus d'informations sur la rotation et le blocage, consultez SpinLock et SpinWait.

Les classes ConcurrentQueue<T> et ConcurrentStack<T> n’utilisent pas de verrous. Au lieu de cela, elles s’appuient sur des opérations Interlocked pour assurer la cohérence des threads.

Remarque

Étant donné que les classes de collections simultanées prennent en charge ICollection, elles fournissent des implémentations pour les propriétés IsSynchronized et SyncRoot, même si ces propriétés ne sont pas pertinentes. IsSynchronized retourne toujours false et SyncRoot est toujours null (Nothing en Visual Basic).

Le tableau suivant répertorie les types de collection dans l'espace de noms System.Collections.Concurrent :

Catégorie Descriptif
BlockingCollection<T> Fournit des fonctionnalités de délimitation et de blocage pour tous les types qui implémentent IProducerConsumerCollection<T>. Pour plus d’informations, consultez Vue d’ensemble de BlockingCollection.
ConcurrentDictionary<TKey,TValue> Implémentation thread-safe d’un dictionnaire de paires clé-valeur.
ConcurrentQueue<T> Implémentation thread-safe d’une file d’attente FIFO (premier entré, premier sorti).
ConcurrentStack<T> Implémentation thread-safe d’une pile LIFO (dernier entré, premier sorti).
ConcurrentBag<T> Implémentation thread-safe d’une collection non ordonnée d’éléments.
IProducerConsumerCollection<T> Interface qu’un type doit implémenter pour être utilisé dans un BlockingCollection.
Titre Descriptif
Vue d’ensemble de BlockingCollection Décrit les fonctionnalités fournies par le BlockingCollection<T> type.
Guide pratique pour ajouter et supprimer des éléments d’un concurrentDictionary Décrit comment ajouter et supprimer des éléments d’un ConcurrentDictionary<TKey,TValue>
Guide pratique pour ajouter et prendre des éléments individuellement à partir d’un BlockingCollection Décrit comment ajouter et récupérer des éléments à partir d’une collection bloquante sans utiliser l’énumérateur en lecture seule.
Guide pratique pour ajouter des fonctionnalités englobantes et bloquantes à une collection Décrit comment utiliser n’importe quelle classe de collection comme mécanisme de stockage sous-jacent pour une IProducerConsumerCollection<T> collection.
Guide pratique pour utiliser ForEach pour supprimer des éléments dans un BlockingCollection Décrit comment utiliser foreach (For Each en Visual Basic) pour supprimer tous les éléments d’une collection bloquante.
Guide pratique pour utiliser des tableaux de collections de blocage dans un pipeline Décrit comment utiliser plusieurs collections bloquantes en même temps pour implémenter un pipeline.
Comment faire : créer un pool d’objets à l’aide d’un ConcurrentBag Montre comment utiliser un conteneur simultané pour améliorer les performances dans les scénarios où vous pouvez réutiliser des objets au lieu de créer continuellement des objets.

Référence