【问题标题】:BlockingCollection TryTake returns false instead of block when the collection is empty当集合为空时,BlockingCollection TryTake 返回 false 而不是 block
【发布时间】:2018-05-23 08:51:28
【问题描述】:

BlockingCollection 为空时,我从 BlockingCollection 的 TryTake 方法返回 false,尽管预期的行为是阻塞直到集合填满。

请注意,集合不是上限(这应该会影响 TryAdd 而不是 TryTake),并且为添加操作设置的 Timeout 尚未过去。

这是我对 BlockingCollection 对象的包装:

    public T TryTake(int timeoutMiliseconds)
    {
        var result = default(T);

        if (!_collection.TryTake(out result, timeoutMiliseconds))
        {
            throw new InvalidOperationException("Unable to get item from collection.");
        }

        return result;
    }

有什么想法会导致这种情况吗?

我已经根据这篇文章实现了生产者-消费者模式: Multithread processing of the SqlDataReader - Producer/Consumer design pattern

【问题讨论】:

  • 异常中包含的 message 说明了什么?
  • 我已将其添加到帖子中
  • TryTake 不会抛出这个异常,因为收集它是空的,它会因为其他原因抛出它(在这个方法的文档中描述)
  • 为了他人的利益,上面代码中调用的方法不是BlockingCollection<T>.TryTake。它是一个自定义类的方法,在内部调用BlockingCollection<T>.TryTake,如果在指定的超时期限内无法获取项目,则抛出指定的异常。按照提供的链接查看该代码。我做了并意识到我的答案不适用。
  • 正如@jmcilhinney 提到的,这个异常实际上是在您从链接复制粘贴的TryTake 方法中抛出的。至少阅读您正在复制粘贴的代码,或使用调试器将您指向抛出该异常的代码。

标签: c# task-parallel-library blockingcollection


【解决方案1】:

我终于意识到,正如 SO post 所展示的那样,我从 TryTake 中得到了错误,因为集合已被清空,并且我也将其标记为已完成(通过在集合上调用 CompleteAdding() 方法)。

所以为了解决这个问题,我在完成标志上添加了一个条件。

有人可能会争辩说,TryTake 永远不会返回 false,而已完成标志为 false。我不确定这总是正确的,所以我更愿意在这种情况下抛出错误。

    public T TryTake(int timeoutMiliseconds)
    {
        var result = default(T);

        if (!_collection.TryTake(out result, timeoutMiliseconds) 
            && !_collection.IsAddingCompleted)
        {
            throw new InvalidOperationException("Unable to get item from collection.");
        }

        return result;
    }

请注意,将TryTake 调用放在第一位,将IsAddingCompleted 放在第二位非常重要。否则,第一个条件可能会通过,然后您会立即阻止 TryTake

【讨论】:

  • 这里会不会有竞态条件,TryTake可以返回false,然后集合标记为完成,再检查IsAddingCompleted?
  • 可能是。但是消费者使用此方法取出生产者插入的项目,因此在您描述的情况下,另一个消费者会在您的场景中的当前消费者之前取出该项目..这没关系。
  • 除非你会回default(T)?
  • 是的。此函数的用户应该知道在大多数情况下获得默认值(T)的可能性实际上是空的。
猜你喜欢
  • 1970-01-01
  • 2015-09-21
  • 2011-05-22
  • 2020-05-15
  • 2018-01-17
  • 1970-01-01
  • 2021-06-04
  • 2023-03-20
  • 1970-01-01
相关资源
最近更新 更多