Structures de données pour la programmation parallèle
La version 4 de .NET Framework introduit de nouveaux types très utiles pour la programmation parallèle, notamment un ensemble de classes de collections simultanées, des primitives de synchronisation légères et des types pour l’initialisation tardive. Vous pouvez utiliser ces types avec n’importe quel code d’application multithread, y compris la bibliothèque parallèle de tâches et PLINQ.
Classes de collections simultanées
Les classes de collections de l’espace de noms System.Collections.Concurrent fournissent des opérations d’ajout et de suppression thread-safe qui évitent autant que possible les verrous et, là où ils se révèlent nécessaires, utilisent un verrouillage de granularité fine. Une classe de collection simultanée n’exige pas que le code utilisateur prenne des verrous lorsqu’il accède aux éléments. Les classes de collections simultanées peuvent améliorer considérablement les performances des types comme System.Collections.ArrayList et System.Collections.Generic.List<T> (avec verrouillage implémenté par l’utilisateur) dans le cas où plusieurs threads ajoutent et suppriment des éléments d’une collection.
Le tableau suivant liste les classes de collections simultanées :
Type | Description |
---|---|
System.Collections.Concurrent.BlockingCollection<T> | Fournit des fonctions bloquantes et englobantes pour les collections thread-safe qui implémentent System.Collections.Concurrent.IProducerConsumerCollection<T>. Les threads producteurs se bloquent si aucun emplacement n’est disponible ou que la collection est pleine. Les threads consommateurs se bloquent si la collection est vide. Ce type prend également en charge l’accès non bloquant par les producteurs et les consommateurs. BlockingCollection<T> peut être utilisé comme classe de base ou comme magasin de stockage pour assurer le blocage et la liaison des classes de collection qui prennent en charge IEnumerable<T>. |
System.Collections.Concurrent.ConcurrentBag<T> | Implémentation de conteneur thread-safe qui effectue des opérations Add et Get évolutives. |
System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> | Type dictionnaire simultané et évolutif. |
System.Collections.Concurrent.ConcurrentQueue<T> | File d’attente FIFO simultanée et évolutive. |
System.Collections.Concurrent.ConcurrentStack<T> | Pile LIFO simultanée et évolutive. |
Pour plus d’informations, consultez Collections thread-safe.
Primitives de synchronisation
Les primitives de synchronisation de l’espace de noms System.Threading affinent la concurrence et améliorent les performances en évitant les coûteux mécanismes de verrouillage du code multithread hérité.
Le tableau suivant liste les types de synchronisation :
Type | Description |
---|---|
System.Threading.Barrier | Permet à plusieurs threads de fonctionner en parallèle sur un algorithme en fournissant un point auquel chaque tâche peut signaler son arrivée, puis se bloquer jusqu'à ce qu’une partie ou la totalité des tâches soient arrivées. Pour plus d’informations, voir Cloisonnement. |
System.Threading.CountdownEvent | Simplifie les scénarios de duplication et de jointure en fournissant un mécanisme facile de réunion. Pour plus d'informations, consultez la page CountdownEvent. |
System.Threading.ManualResetEventSlim | Primitive de synchronisation similaire à System.Threading.ManualResetEvent. ManualResetEventSlim est léger mais n’est utilisable que pour la communication intraprocessus. |
System.Threading.SemaphoreSlim | Primitive de synchronisation qui limite le nombre de threads pouvant accéder simultanément à une ressource ou à un pool de ressources. Pour plus d’informations, consultez la page Semaphore et SemaphoreSlim. |
System.Threading.SpinLock | Primitive de verrou mutex obligeant le thread qui essaie d’acquérir le verrou à attendre dans une boucle ou à rester en attente active pendant un certain temps avant de transmettre son quantum. Dans les scénarios où l’attente du verrou est censée être courte, SpinLock offre de meilleures performances que les autres types de verrouillage. Pour plus d'informations, consultez la page SpinLock. |
System.Threading.SpinWait | Type petit et léger qui restera en attente active pendant un certain temps et mettra le thread dans un état d’attente si le nombre est dépassé. Pour plus d'informations, consultez la page SpinWait. |
Pour plus d'informations, consultez les pages suivantes :
Comment : utiliser le verrouillage spinlock pour une synchronisation de bas niveau
Guide pratique : Synchroniser des opérations simultanées avec un objet Barrier
Classes d’initialisation tardive
Avec l’initialisation tardive, la mémoire d’un objet n’est pas allouée tant qu’elle n’est pas nécessaire. L’initialisation tardive peut améliorer les performances en répartissant uniformément les allocations d’objets sur toute la durée de vie d’un programme. Vous pouvez l’activer sur n’importe quel type personnalisé en incluant le type Lazy<T> dans un wrapper.
Le tableau suivant liste les nouveaux types d’initialisation tardive :
Type | Description |
---|---|
System.Lazy<T> | Assure une initialisation tardive légère et thread-safe. |
System.Threading.ThreadLocal<T> | Fournit une valeur initialisée tardivement thread par thread, chacun appelant de façon tardive la fonction d’initialisation. |
System.Threading.LazyInitializer | Fournit des méthodes statiques qui évitent d’avoir à allouer une instance dédiée d’initialisation tardive. Utilise plutôt des références pour vérifier que les cibles ont été initialisées lorsqu’elles sont consultées. |
Pour plus d’informations, consultez Initialisation tardive.
Agréger des exceptions
Le type System.AggregateException permet de capturer plusieurs exceptions levées simultanément sur des threads distincts, et de les retourner au thread de jonction comme une seule exception. Les types System.Threading.Tasks.Task et System.Threading.Tasks.Parallel ainsi que PLINQ utilisent beaucoup AggregateException pour cela. Pour plus d’informations, consultez Gestion des exceptions et Comment gérer des exceptions dans une requête PLINQ.