如果其基础集合不为空但 TryTake 失败,BlockingCollection 是否会重试?

Does BlockingCollection re-try if its underlying collection is not empty but TryTake fails?

BlockingCollection is a wrapper around IProducerConsumerCollection。我的理解是调用 BlockingCollection.Take 检查是否有可用的项目(使用它自己的计数器)。然后它在其基础集合上使用 TryTake 来检索所述项目。

现在当然必须在基础集合中实际存在一个项目(并且没有发生外部修改)。但是,如果 TryTake 由于某些其他原因而失败,并且基础集合 returns 为 TryTake false,会发生什么情况?包装器是直接放弃,还是尝试再次拿走该物品(据说下次会成功)?

不祥的 "other reason" 可能是内部延迟,例如如果数据结构是分布式的。

好吧,您唯一可以认为理所当然的就是文档中所写的内容。但是你可以看看 the source code:

public T Take()
{
    T item;

    if (!TryTake(out item, Timeout.Infinite, CancellationToken.None))
    {
        throw new InvalidOperationException(SR.GetString(SR.BlockingCollection_CantTakeWhenDone));
    }

    return item;
}

也就是说,TryTake returns false 的原因是无关紧要的; Take 会抛出。

@Joey 的回答链接到源代码并给出了正确的结果,但问题有点微妙。

BC.Take 调用 BC.TryTake 而非基础集合上的 )。 BC.TryTake 然后等待信号量。当一个项目被添加到 BC 时,这个信号量会增加。

然后调用 Underlying.TryTakethrows directly if that returns false。缩写:

//If an item was successfully removed from the underlying collection.
removeSucceeded = m_collection.TryTake(out item);
if (!removeSucceeded) {
    // Check if the collection is empty which means that the collection was modified outside BlockingCollection
    throw new InvalidOperationException (SR.GetString(SR.BlockingCollection_Take_CollectionModified));
}

这是公元前唯一一个叫Underlying.TryTake的地方。

所以TryTake确实是绝对不允许失败的。但是,(通过当前的 BC 代码)保证 TryTake 仅在相应的 TryAdd 之后调用。所以底层数据结构只需要确保 TryTake 的操作永远不会延迟到 TryAdd 的操作结束之后,因为 BC 不会尝试 TryTake 而 [=18] =] 的唯一元素仍在进行中