BlockingCollection <t>使用TPL DataFlow进行批处理</t>

时间:2014-02-11 14:01:41

标签: c# task-parallel-library blockingcollection

有没有办法从阻止集合中批处理一组项目。 E.G。

我有一个消息总线发布者呼叫     blockingCollection.Add()

这是一个像这样创建的消费线程:

Task.Factory.StartNew(() =>
        {
            foreach (string value in blockingCollection.GetConsumingEnumerable())
                {
                    Console.WriteLine(value);
                }
        });

但是,我只希望控制台在阻塞集合上有10个项目后写入,而GetConsumingEnumerable()总是在每个项目添加后触发。我可以为此编写自己的队列但是如果可能的话我想使用阻塞集合吗?

2 个答案:

答案 0 :(得分:4)

快速解决方案就是这样的

public class ConsoleQueue
{
    private readonly List<string> _values = new List<string>();

    public void FlushQueueIfFull()
    {
        if (_values.Count < 10) return;
        foreach (var value in _values)
        {
            Console.WriteLine(value);
        }
        _values.Clear();
    }

    public void Push(string message)
    {
        _values.Add(message);
        FlushQueueIfFull();
    }
}

那么你可以像这样使用它

        var queue = new ConsoleQueue();

        Task.Factory.StartNew(() =>
        {
            foreach (string value in blockingCollection.GetConsumingEnumerable())
            {
                queue.Push(value);
            }
        });

您可以轻松扩展它以涵盖线程安全等

答案 1 :(得分:3)

不确定项目要求是什么,但我建议TPL DataFlow BatchBlock

您将实例化BatchBlock<string>,将其绑定到ActionBlock<string>,然后发布到批处理块。

伪代码可能如下所示:

var bb = new BatchBlock<string>(10);
var ab = new ActionBlock<string[]>(msgArray=>{ 
    foreach(var msg in msgArray) 
        Console.Writeline(msg);
});

bb.LinkTo(ab);

foreach (string value in blockingCollection.GetConsumingEnumerable())
{
      bb.Post(value);
}

使用DataFlow,您甚至可能希望将BlockingCollection替换为BufferBlock,或者只是直接发布到缓冲区块而无需先添加阻塞集合,因为批处理块已经是线程安全的。