我试图在.NET 4上的新并行堆栈的上下文中理解BlockingCollection的目的。
MSDN文档说:
BlockingCollection用作IProducerConsumerCollection实例的包装器,允许从集合中删除尝试以阻止数据可用于删除。类似地,可以创建BlockingCollection以强制执行IProducerConsumerCollection中允许的数据元素数量的上限;然后可以阻止对集合的添加尝试,直到空间可用于存储添加的项目。
但是当我查看一些IProducerConsumerCollection的实现时,比如ConcurrentQueue,我看到它们提供了一个无锁,线程安全的实现。那么为什么需要BlockingCollection提供的锁机制呢? MSDN中的所有示例都显示通过BlockingCollection包装器使用这些集合,直接使用这些集合有哪些麻烦?使用BlockingCollection会产生什么好处?
答案 0 :(得分:18)
阻止直到可以执行操作是一种方便,如果您无其他任何事情要做(或者更确切地说:在执行操作之前无法继续)。
如果你有一个非阻塞队列,你想从中读取数据,并且目前没有数据,你必须定期轮询它,或等待一些信号量,直到有数据。如果队列阻塞,那就已经自动完成了。
同样,如果您尝试添加到已满的非阻塞队列,则操作将失败,然后您必须弄清楚要执行的操作。阻塞队列只会等到有空间。
如果您有一些聪明的事情而不是等待(例如检查另一个队列的数据,或者引发QueueTooFullException),那么您需要非阻塞队列,但通常情况并非如此。
通常,有一种方法可以指定阻塞队列的超时。
答案 1 :(得分:7)
锁定的目的是锁定本身。您可以从集合中读取多个线程,如果没有可用数据,则线程将保持锁定状态,直到新数据到达。
此外,通过设置大小限制的功能,您可以让填充集合的生产者线程尽可能多地添加到其中。当集合达到限制时,线程将直接锁定,直到消费者线程为数据腾出空间。
通过这种方式,您可以使用该集合来限制数据的吞吐量,而无需自行检查。你的线程只是随便读写,并且集合负责根据需要保持线程正常工作或休眠。
答案 2 :(得分:4)
这是你做过之后更容易理解的事情之一。
对于生产者消费者,让我们有两个对象,生产者和消费者。它们都共享一个它们在构造时给出的队列,因此它们可以在它之间写入。
添加一个生产者消费者是非常熟悉的,只需要与CompleteAdding略有不同:
public class Producer{
private BlockingCollection<string> _queue;
public Producer(BlockingCollection<string> queue){_queue = queue;}
//a method to do something
public MakeStuff()
{
for(var i=0;i<Int.MaxValue;i++)
{
_queue.Add("a string!");
}
_queue.CompleteAdding();
}
}
消费者似乎没有意义 - 直到你意识到foreach不会停止循环UNTIL队列已完成添加。在那之前,如果没有物品,它就会重新入睡。而且由于它与生产者和消费者中的集合实例相同,因此您可以让消费者在实际操作时只占用周期,而不必担心停止它,重新启动它等等。
public class Consumer()
{
private BlockingCollection<string> _queue;
public Consumer(BlockingCollection<string> queue)
{
_queue = queue;
}
public void WriteStuffToFile()
{
//we'll hold until our queue is done. If we get stuff in the queue, we'll start processing it then
foreach(var s in _queue.GetConsumingEnumerable())
{
WriteToFile(s);
}
}
}
因此,您可以使用该集合将它们连接在一起。
var queue = new BlockingCollection<string>();
var producer = new Producer(queue);
var consumer = new Consumer(queue);
producer.MakeStuff();
consumer.WriteStuffToFile();
答案 3 :(得分:0)
或者,AsyncEx提供AsyncCollection,它是BlockingCollection的异步版本。见https://github.com/StephenCleary/AsyncEx/wiki/AsyncCollection