调用 CompleteAdding() 时如何处理 BlockingCollection<> 中的剩余数据

How to process remaining data in the BlockingCollection<> when CompleteAdding() has been called

BlockingCollection<> 在收到来自 CompleteAdding() 方法的调用时忽略处理底层队列中的剩余数据。以下代码是消费者方法的一部分:

while (blockingCollection.TryTake(out item Item))
{
    //Do something with item.
}

相反,我想以一种处理所有剩余项目的方式更改它 AFTER 生产者问题 CompleteAdding() 方法,以及 ONLY THEN 跳出循环。

不是消耗 BlockingCollection<T>:

的正确方法
while (blockingCollection.TryTake(out item Item))
{
    // Do something with item
}

上面的循环会在 blockingCollection 暂时没有物品的任何时候退出。正确的做法是枚举GetConsumingEnumerable():

foreach (var item in blockingCollection.GetConsumingEnumerable())
{
    // Do something with item
}

blockingCollection 被标记为 CompleteAdding 并且所有可用项目都已处理时,上述循环退出。如果 blockingCollection 在任何时候暂时为空,循环将阻塞当前线程,同步等待新项目或 CompleteAdding() 信号。

下面介绍了一种更专业的循环变体。如果不活动,它会每隔几秒记录一条消息,这样您就知道消费者没有死,只是闲着。

while (true)
{
    while (blockingCollection.TryTake(out item Item, TimeSpan.FromSeconds(10)))
    {
        // Do something with item
    }
    if (blockingCollection.IsCompleted) break;

    // Log a heartbeat
}