如何使用BlockingCollection <t>来阻止所有生成器,直到所有项都被消耗(批量消耗)?</t>

时间:2015-04-06 20:10:00

标签: c# producer-consumer blockingcollection

我已经阅读了其他一些类似但不相同的链接,试图找到一些答案: How to consume a BlockingCollection<T> in batches

然而,(在上面的链接中)没有使用GetConsumingEnumerable似乎很可疑。

在消费者(应该是单数)清空收藏品时,有效阻止生产者的正确方法是什么?

[我们希望进行批处理,因为每个批处理都会进行一次Web服务调用,如果每个消息/项目都需要自己的调用,这将成为瓶颈。批量处理消息/项目是解决此瓶颈的方法。]

理想情况下:

1)接收消息

2)推进集合的新生产者任务

3)当收集&#39;完整&#39; (任意限制),阻止所有生产者,新的消费者任务消耗所有的集合,然后取消阻止生产者。

换句话说;我希望(并行生产者)xor(单一消费者)随时对集合采取行动。

这似乎应该在此之前完成,但我似乎无法找到专门以这种方式行事的代码段。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

使用这个模型,所有的工作都是完全序列化的,也就是说你从来没有一个以上的东西&#34;一次工作。生产者是工作,还是消费者。因此,您并不需要从生产者和消费者那里操作的集合,而是可以让生产者生成批量的传统集合,消费者在完成后会消耗这些集合。它可能看起来像这样:

public Task<List<Thing>> Produce(Message message)
{
    //...
}

public Task Consume(List<Thing> data)
{
    //...
}

public async Task MessageReceived(Message message)
{
    while(HaveMoreBatches(message))
    {
        await Consume(await Produce(message));
    }
}

这使您可以生成批次,然后使用它,然后生成另一个批次,然后使用它等,直到不再生成批次为止。

答案 1 :(得分:0)

根据你的模糊描述,我相信双缓冲是你想要的。

只需创建两个缓冲区。生产者写到一个直到。当它变满或当计时器退出时,它会被“交换”为第二个,并且生产者开始写入新的。然后消费者开始阅读第一个现在已满的缓冲区。

这允许生产者和消费者同时运行。并确保消费者在重复循环之前处理所有先前创建的工作。