BlockingCollection <t>中的IsCompleted属性是否实际阻塞?

时间:2017-08-23 14:02:54

标签: c# blocking producer-consumer

我正在尝试为我正在异步读取控制器的数据流实现生产者/消费者模式。我想使用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方法中获取无效的数据,而这种方法没有选择(如果消费者不知道已完成的状态)。我觉得我很难解释我在这里担心的事情......

1 个答案:

答案 0 :(得分:2)

  

IsCompleted属性是否实际阻止?

不,它会立即返回。

  

因此,如果另一个线程要访问缓冲区,我希望它在调用Take方法之前等待并确保缓冲区实际上没有“完成”。

就是这样。当然,如果在致电IsCompleted时缓冲区未完成,则会返回false。它可能在 之后完成它已返回该值,并且在您调用IsCompleted时队列中可能没有任何项目。

  

在我的应用程序中,期望的效果是允许我在缓冲区实际为空时避免构造新的消息对象。

如果集合被阻止并且其中没有项目,

Take将抛出异常,因此您无需担心这一点。它不会永远阻塞,也不会在没有任何实际数据的情况下构造新的消息。您可以在循环之外捕获异常,以便在完成后继续。

所有这一切,让BlockingCollection为你处理迭代更容易,而不是试图构建你自己的消费迭代器(即使它不是 很难做到这一点你自己)。你可以写:

foreach(var data in buffer.GetConsumingEnumerable())
    //...

它会消耗序列中的项目,直到缓冲区完成,然后在没有,也不会是缓冲区中的任何项目的情况下中断循环。