添加到集合完成后从 BlockingCollection.TakeFromAny 正常退出

Graceful exit from BlockingCollection.TakeFromAny when adding to collections completed

我使用 BlockingCollection.TakeFromAny 在循环中等待两个 BlockingCollections 中的可用项目。项目被添加到其他主题的集合中。在某些时候,我完成了对集合的添加,并在下一次调用 TakeFromAny 时,我的代码卡住了,并且没有 return 从它。

我尝试将 CompleteAdding 用于两个集合或将 TakeFromAnyCancellationToken 参数一起使用,但在这两种情况下都会发生异常:

All collections are marked as complete with regards to additions. Parameter name: collections

是否可以通过某种方式设置集合,使我的代码无一例外地从 TakeFromAny 中取出,并带有一个 return 值,表明基础集合中不会有任何新项目?

TryTakeFromAny 不适合我的需要,因为它总是 returns 当集合当前为空但项目仍将在以后添加时。我想阻止直到下一个项目可用或没有要添加的东西。

TryTakeFromAny is not suitable for my needs as it always returns when it happens that the collections are currently empty but items still will be added later. I want to block until the next item is available or there is nothing to add.

TryTakeFromAny() 方法具有允许您指定超时值的重载。该方法不会 return 直到有一个值被 returned,或者超过超时期限。

对于这些重载,如果您指定 -1 毫秒的超时,该方法将无限期等待。如果任一集合调用了 CompleteAdding() 方法,它不会抛出异常,如果传递给它的所有集合都调用了 return -1 作为集合索引值,它不会抛出异常。 =13=] 调用了方法。

一个简单的例子来说明这个工作原理:

static void Main(string[] args)
{
    BlockingCollection<int> c1 = new BlockingCollection<int>(), c2 = new BlockingCollection<int>();

    Task task = Produce(c1, c2);

    while (BlockingCollection<int>.TryTakeFromAny(new[] { c1, c2 }, out int value, -1) >= 0)
    {
        Console.WriteLine($"value: {value}");
    }

    Console.WriteLine($"task.IsCompleted: {task.IsCompleted}");
    task.Wait();
}

private static async Task Produce(BlockingCollection<int> c1, BlockingCollection<int> c2)
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    c1.Add(1);
    await Task.Delay(TimeSpan.FromSeconds(1));
    c1.CompleteAdding();
    await Task.Delay(TimeSpan.FromSeconds(1));
    c2.Add(2);
    await Task.Delay(TimeSpan.FromSeconds(1));
    c2.CompleteAdding();
}