web-dev-qa-db-fra.com

Quand utiliser BlockingCollection et quand ConcurrentBag au lieu de List <T>?

Le réponse acceptée à la question "Pourquoi ce code Parallel.ForEach gèle-t-il le programme?" conseille de remplacer l'utilisation de la liste par ConcurrentBag dans une application WPF.

Je voudrais savoir si un BlockingCollection peut être utilisé dans ce cas à la place?

40
Fulproof

Vous pouvez en effet utiliser un BlockingCollection, mais cela ne sert à rien.

Tout d'abord, notez que BlockingCollection est un wrapper autour d'une collection qui implémente IProducerConsumerCollection<T> . Tout type qui implémente cette interface peut être utilisé comme stockage sous-jacent:

Lorsque vous créez un BlockingCollection<T> objet, vous pouvez spécifier non seulement la capacité limitée mais également le type de collection à utiliser. Par exemple, vous pouvez spécifier un ConcurrentQueue<T> objet pour le comportement premier entré, premier sorti (FIFO), ou un ConcurrentStack<T> objet pour le comportement dernier entré, premier sorti (LIFO). Vous pouvez utiliser n'importe quelle classe de collection qui implémente le IProducerConsumerCollection<T> interface. Le type de collection par défaut pour BlockingCollection<T> est ConcurrentQueue<T>.

Ceci comprend ConcurrentBag<T>, ce qui signifie que vous pouvez avoir un sac simultané bloquant. Alors, quelle est la différence entre un simple IProducerConsumerCollection<T> et une collection bloquante? La documentation de BlockingCollection dit (soulignement le mien):

BlockingCollection<T> est utilisé comme wrapper pour un IProducerConsumerCollection<T> instance, permettant de bloquer les tentatives de suppression de la collection jusqu'à ce que les données soient disponibles pour être supprimées . De même, un BlockingCollection<T> peut être créé pour appliquer une limite supérieure sur le nombre d'éléments de données autorisés dans le IProducerConsumerCollection<T> [...]

Étant donné que dans la question liée, il n'est pas nécessaire de faire l'une ou l'autre de ces choses, l'utilisation de BlockingCollection ajoute simplement une couche de fonctionnalités qui n'est pas utilisée.

70
Jon
  • List<T> est une collection conçue pour être utilisée dans des applications à un seul thread.

  • ConcurrentBag<T> est un sous-type de ConcurrentCollection<T> conçu pour simplifier l'utilisation des collections dans des environnements multi-threads. Si vous utilisez ConcurrentCollection, vous n'aurez pas à verrouiller votre collection pour éviter la corruption par d'autres threads. Vous pouvez insérer ou prendre des données de votre collection sans avoir besoin d'écrire des codes de verrouillage spéciaux.

  • BlockingCollection<T> est conçu pour supprimer l'exigence de vérifier si de nouvelles données sont disponibles dans la collection partagée entre les threads. s'il y a de nouvelles données insérées dans la collection partagée, votre thread consommateur se réveillera immédiatement. Vous n'avez donc pas à vérifier si de nouvelles données sont disponibles pour le thread consommateur à certains intervalles de temps, généralement dans une boucle while.
14
Ahmet Arslan

Oui, vous pouvez utiliser BlockingCollection pour cela. finishedProxies serait défini comme:

BlockingCollection<string> finishedProxies = new BlockingCollection<string>();

et pour ajouter un article, vous écririez:

finishedProxies.Add(checkResult);

Et quand c'est fait, vous pouvez créer une liste à partir du contenu.

3
Jim Mischel