C# 批量生产者/消费者模式

C# 批量生产者/消费者模式,c#,multithreading,thread-safety,task-parallel-library,task,C#,Multithreading,Thread Safety,Task Parallel Library,Task,我正试图实现一个具有多个生产者和一个消费者的相当简单的生产者/消费者风格的应用程序 通过研究,我发现了BlockingCollection,它非常有用,并允许我执行一项长期运行的消费者任务,如下所示: var c1 = Task.Factory.StartNew(() => { var buffer = new List<int>(BATCH_BUFFER_SIZE); foreach (var value in blockingCollection.GetC

我正试图实现一个具有多个生产者和一个消费者的相当简单的生产者/消费者风格的应用程序

通过研究,我发现了
BlockingCollection
,它非常有用,并允许我执行一项长期运行的消费者任务,如下所示:

var c1 = Task.Factory.StartNew(() =>
{
    var buffer = new List<int>(BATCH_BUFFER_SIZE);

    foreach (var value in blockingCollection.GetConsumingEnumerable())
    {
        buffer.Add(value);
        if (buffer.Count == BATCH_BUFFER_SIZE)
        {
            ProcessItems(buffer);
            buffer.Clear();
        }
    }
});
这有一个明显的问题,
foreach
将被阻塞到最后,从而破坏计时器的功能


有人能提供一个方向吗?我基本上需要定期快照
BlockingCollection
,然后处理内容并清除它。也许
BlockingCollection
是错误的类型?

不要在计时器回调中使用
getconsumineGenumerable
,而是使用以下方法之一,将结果添加到列表中,直到返回
false
或达到满意的批处理大小

-可能是您需要的,您根本不想执行进一步的等待

您可以轻松地将其提取到扩展中(未经测试):

公共静态IList刷新
(此BlockingCollection集合,int-maxSize=int.MaxValue)
{
//参数检查。
T下一步;
var result=新列表();
while(result.Count
我使用了这个非常有效的实现。它每x秒运行一次,只推送可用的内容(无需等待)。谢谢你的帮助。一个完整的工作版本现在可以在我相信你的代码例子将受到比赛条件由于定时器机制。如果您的使用者无法在计时器周期内完成任务,则计时器将触发,而不管是否导致生成另一个使用者。@安德鲁:这取决于所使用的计时器实现,它不在本回答的范围内,这与阻塞集合本身有关。
syncTimer = new Timer(new TimerCallback(TimerElapsed), blockingCollection, 5000, 5000);

private static void TimerElapsed(object state)
{
    var buffer = new List<int>();
    var collection = ((BlockingCollection<int>)state).GetConsumingEnumerable();

    foreach (var value in collection)
    {
        buffer.Add(value);
    }

    ProcessItems(buffer);
    buffer.Clear();
}
public static IList<T> Flush<T>
(this BlockingCollection<T> collection, int maxSize = int.MaxValue)
{
     // Argument checking.

     T next;
     var result = new List<T>();

     while(result.Count < maxSize && collection.TryTake(out next))
     {
         result.Add(next);
     }

     return result;
}