BlockingCollection<T> 中的 IsCompleted 属性 是否真的阻塞了?

Does the IsCompleted property in the BlockingCollection<T> actually block?

我正在尝试为我从控制器异步读取的数据流实施 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 方法之前等待并确保缓冲区实际上不是 "completed"。

在我的应用程序中,期望的效果是允许我避免在缓冲区实际上为空时构造新的消息对象。所以这就是为什么我在尝试 Take.

之前检查 IsCompleted

此外...我了解到 Take 方法不再阻塞一次 IsAddingCompleted = true。所以我不希望消费者从无效的 Take 方法中获取数据,它别无选择(如果消费者不知道完成状态)。我想我真的很难解释我在这里担心的事情......

Does the IsCompleted property actually block?

不,它会立即return。

So that if another thread was going to access the buffer, I would like it to wait and make sure that the buffer is actually not "completed" before calling on the Take method.

这样做。当然,如果调用 IsCompleted 时缓冲区未完成,它将 return false。它可能 具有 return 那个值之后完成,并且在您调用 IsCompleted.[=20 时队列中可能没有任何项目=]

In my application, the desired effect would be to allow me to avoid constructing a new message object when the buffer is in fact empty.

Take 如果集合被阻塞并且其中没有任何项目,则会抛出异常,因此您无需担心。它不会永远阻塞,也不会在没有任何实际数据的情况下构造新消息。您可以在循环外捕获异常以在完成后继续。

综上所述,让 BlockingCollection 为您处理迭代要容易得多,而不是尝试构建您自己的消费迭代器(即使它不是 很难自己做)。你可以只写:

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

它将消耗序列中的项目,直到缓冲区完成,然后在缓冲区中没有并且永远不会有任何项目时跳出循环。