首页 > 解决方案 > 当集合为空时,BlockingCollection TryTake 返回 false 而不是 block

问题描述

当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;
    }

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

我已经实现了生产者-消费者模式,基于这篇文章: SqlDataReader 的多线程处理 - 生产者/消费者设计模式

标签: c#task-parallel-libraryblockingcollection

解决方案


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

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

有人可以争辩说,当已完成标志为 false 时,TryTake​​永远不会返回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


推荐阅读