阻止集合中的Take / TryTake和Add / TryAdd之间的区别

时间:2018-01-17 12:20:34

标签: c# .net multithreading asynchronous blockingcollection

我一直试图绕过Blocking Collection,我遇到了Take()TryTake() Add()TryAdd()

据我所知,如果没有可以使用的项目,Take()将等待添加项目,与Add()类似,如果集合已达到其最大限制,它将等到该项目为除去。

根据Josheph Albahari's article on Parallel Programming

  

“如果集合大小有限,Add和TryAdd可能会阻止; Take和   当集合为空时,TryTake阻止。“

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

3 个答案:

答案 0 :(得分:4)

TryTake不等待,如果收藏什么都没有,立即会返回falseTake会等待一个项目。

TryTake:

  

如果集合为空,则此方法立即返回false。

采取:

  

对Take的调用可能会阻止,直到某个项目可以删除。

答案 1 :(得分:4)

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

答案 2 :(得分:1)

我偶然发现了这个问题,我认为Microsoft的这份文档确实有助于弄清科学背后的情况。

如果不存在任何项目,已达到有界集合的最大容量或已经过了超时时间,则TryAdd或TryTake操作将返回false。这样一来,线程可以执行一些其他有用的工作,然后稍后再试一次以检索新项目或尝试添加以前无法添加的相同项目。

How to Add and Take Items Individually from a BlockingCollection