我正在尝试为我正在异步读取控制器的数据流实现生产者/消费者模式。我想使用BlockingCollection<T>
来执行此操作,但我希望确保获得所需的结果。我的消费者看起来像这样:
// make sure there is actually some data in the buffer
if (!this.buffer.IsCompleted)
{
// attempt to read from the buffer
data = this.buffer.Take();
// construct the message object
message = this.ConvertToMessageObject(data);
}
IsCompleted
属性是否实际阻止?因此,如果另一个线程要访问缓冲区,我希望它等待并确保在调用Take
方法之前缓冲区实际上没有“完成”。
在我的应用程序中,期望的效果是允许我在缓冲区实际为空时避免构造新的消息对象。所以这就是我在去IsCompleted
之前检查Take
的原因。
此外...我了解Take
方法不再阻止IsAddingCompleted = true
。所以我不希望消费者从Take
方法中获取无效的数据,而这种方法没有选择(如果消费者不知道已完成的状态)。我觉得我很难解释我在这里担心的事情......
答案 0 :(得分:2)
IsCompleted
属性是否实际阻止?
不,它会立即返回。
因此,如果另一个线程要访问缓冲区,我希望它在调用Take方法之前等待并确保缓冲区实际上没有“完成”。
就是这样。当然,如果在致电IsCompleted
时缓冲区未完成,则会返回false
。它可能在 之后完成它已返回该值,并且在您调用IsCompleted
时队列中可能没有任何项目。
如果集合被阻止并且其中没有项目,在我的应用程序中,期望的效果是允许我在缓冲区实际为空时避免构造新的消息对象。
Take
将抛出异常,因此您无需担心这一点。它不会永远阻塞,也不会在没有任何实际数据的情况下构造新的消息。您可以在循环之外捕获异常,以便在完成后继续。
所有这一切,让BlockingCollection
为你处理迭代更容易,而不是试图构建你自己的消费迭代器(即使它不是 很难做到这一点你自己)。你可以写:
foreach(var data in buffer.GetConsumingEnumerable())
//...
它会消耗序列中的项目,直到缓冲区完成,然后在没有,也不会是缓冲区中的任何项目的情况下中断循环。