Take/TryTake 和 Add/TryAdd 在阻塞 Collection 上的区别

Difference between Take/TryTake and Add/TryAdd on a Blocking Collection

我一直在努力了解 Blocking Collection,我遇到了 Take()TryTake(),还有 Add()TryAdd()

我知道如果没有物品可以带走,Take()会等到有物品被添加,与Add()类似,如果collection已经达到最大限制,它将等到项目被删除。

根据Josheph Albahari's article on Parallel Programming

"Add and TryAdd may block if the collection size is bounded; Take and TryTake block while the collection is empty."

因此 Take()TryTake() 都在等待添加项目。那么,如果我们不提供任何超时或取消令牌,Take()TryTake() 之间有什么区别,难道 TryTake() return false 不应该直接而不等待吗? TryAdd() ?

也一样

TryTake does not wait, it immediately returns false if collection has nothing. Take 将等待一个项目。

试拍:

If the collection is empty, this method immediately returns false.

取:

A call to Take may block until an item is available to be removed.

Take 将通过抛出 InvalidOperationException 来表示队列完成。如果您将异常选项卡配置为抛出捕获的异常,这会使调试变得有点困难。

因此,我确实尝试使用TryTake。事实证明 BlockingCollection<T>.Take 实际上确实使用了 TryTake,但超时是无限的。所以与其这样写:

while (!queue.IsCompleted)
{
    object obj;

    try
    {
        obj = queue.Take();
    }
    catch (InvalidOperationException)
    {
        continue;
    }

    // Do something with obj.
}

您可以按如下方式使用TryTake

while (!queue.IsCompleted)
{
    if (!queue.TryTake(out var obj, Timeout.InfiniteTimeSpan))
        continue;

    // Do something with obj.
}

使代码更简洁并且不会抛出 InvalidOperationException

我偶然发现了这个问题,我认为微软的这篇文档对弄清楚科学背后发生的事情非常有帮助。

If no item is present, maximum capacity on a bounded collection has been reached, or the timeout period has elapsed, then the TryAdd or TryTake operation returns false. This allows the thread to do some other useful work for a while and then try again later to either retrieve a new item or try to add the same item that could not be added previously.

How to Add and Take Items Individually from a BlockingCollection