C# 何时使用BlockingCollection,何时使用ConcurrentBag而不是List<;T>;?

C# 何时使用BlockingCollection,何时使用ConcurrentBag而不是List<;T>;?,c#,wpf,multithreading,linq,task-parallel-library,C#,Wpf,Multithreading,Linq,Task Parallel Library,建议在WPF应用程序中使用替换列表用法 我想知道在这种情况下是否可以使用a 是的,您可以使用BlockingCollection已完成的验证将定义为: BlockingCollection<string> finishedProxies = new BlockingCollection<string>(); 完成后,您可以根据内容创建一个列表。您确实可以使用BlockingCollection,但这样做绝对没有意义 首先,请注意,这是一个围绕实现的集合的包装器。实现该接

建议在WPF应用程序中使用替换列表用法


我想知道在这种情况下是否可以使用a

是的,您可以使用
BlockingCollection
<代码>已完成的验证将定义为:

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

完成后,您可以根据内容创建一个列表。

您确实可以使用
BlockingCollection
,但这样做绝对没有意义

首先,请注意,这是一个围绕实现的集合的包装器。实现该接口的任何类型都可以用作基础存储:

创建
BlockingCollection
对象时,可以指定 不仅是有限容量,而且是要使用的集合类型。对于 例如,您可以为first-in指定一个
ConcurrentQueue
对象, 先进先出(FIFO)行为,或最后一个对象的
ConcurrentStack
对象 先进先出(LIFO)行为。您可以使用任何 实现
IProducerConsumerCollection
接口。默认值
BlockingCollection
的收集类型为
ConcurrentQueue

这包括
ConcurrentBag
,这意味着您可以拥有一个阻塞并发包。那么普通的
IProducerConsumerCollection
和阻塞集合之间有什么区别呢?
BlockingCollection
的文档说明(重点是我的):

BlockingCollection
用作
IProducerConsumerCollection
实例,允许删除尝试 从集合到块,直到可以删除数据。 类似地,可以创建
BlockingCollection
,以强制执行 中允许的数据元素数的上限
IProducerConsumerCollection
[…]

由于在链接问题中不需要执行这两项操作,因此使用
BlockingCollection
只需添加一层未使用的功能即可。

  • 列表
    是设计用于单线程的集合 应用程序

  • ConcurrentBag
    是一类
    集合。Concurrent
    命名空间 简化多线程环境中集合的使用。如果你 使用ConcurrentCollection,您不必锁定 收集以防止其他线程损坏。您可以插入 或者从您的收集中获取数据,而无需编写特殊的锁定代码

  • BlockingCollection
    旨在消除检查线程之间共享集合中是否存在新数据的要求。如果有新数据插入到共享集合中,那么您的消费者线程将立即唤醒。所以,您不必检查消费者线程在特定时间间隔(通常在while循环中)是否有新数据可用


每当您发现需要线程安全的
列表时,在大多数情况下,
ConcurrentBag
BlockingCollection
都不是您的最佳选择。这两个集合都专门用于简化生产者-消费者场景,因此,除非您有多个线程同时添加和从集合中删除项目,否则您应该寻找其他选项(在大多数情况下,最佳候选线程是最合适的)

特别是对于,它是一个非常专门的类,针对混合的生产者-消费者场景,这意味着每个工作线程既是生产者又是消费者。对于类的内部存储来说,它可能是一个很好的候选者,但除此之外,很难想象这个类有什么有利的使用场景。例如,使用它来存储
Parallel.ForEach
循环的结果是一个错误的选择,因为该类没有针对这种用法进行优化。
ConcurrentQueue
不仅效率更高,而且在保持插入项的顺序方面也做得更好

人们通常认为
ConcurrentBag
是线程安全的等价物,相当于
列表
,但事实并非如此。这两种API的相似性具有误导性。调用
Add
列表
将导致在列表末尾添加项目。调用
ConcurrentBag
会导致添加到包内随机插槽中的项目。
ConcurrentBag
基本上是无序的。它没有针对枚举进行优化,当命令它这样做时,它的工作很糟糕。它在内部维护大量线程本地队列,因此其内容的顺序由哪个线程做了什么决定,而不是什么时候发生了什么

一个更好的线程安全替代
列表。Add
就是这个方法。“Enqueue”是一个比“Add”更不熟悉的词(更难发音!),但它实际上做了你期望它做的事情


没有什么是
ConcurrentBag
能做的,而
ConcurrentQueue
不能做的。例如,两个集合都不提供从集合中删除的方法。如果你想要一个带有
TryRemove
方法且带有
参数的并发集合,你应该看看这个类。

@Jon,谢谢,这帮我从白痴状态中解脱出来,当我真的需要ConcurrentDictionaryJim Mischel时,不再浪费时间学习ConcurrentBag和阻止collection,读你的书。我希望我能早点找到它,因为它非常接近我的实际需要。我从反编译器中看不到
ConcurrentCollection
的类:公共类ConcurrentBag:IProducerConsumercCollection,IEnumerable,IEnumerable,ICollection,iReadonlyCollection我仍然给出+1-这有助于澄清消费者线程关于BlockingCollection的觉醒,谢谢!
finishedProxies.Add(checkResult);