如果其基础集合不为空但 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.TryTake
和 throws 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] =] 的唯一元素仍在进行中。
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.TryTake
和 throws 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] =] 的唯一元素仍在进行中。