在等待多个输入时如何使用TPL TransformBlock?

时间:2015-08-05 07:56:00

标签: .net task-parallel-library tpl-dataflow

如果我有多个数据源(例如来自数据库),然后执行一些CPU绑定工作,我如何使用TPL DataFlow表示这个?

我注意到TransformBlock有一个输入源,但是输入来自多个源,我想做大部分的并行操作来实现这个目的。

使用常规TPL或并行扩展来执行数据库的IO绑定工作,然后将这些数据合并到TransformBlock的一个点是最好的方法吗?

1 个答案:

答案 0 :(得分:2)

看看JoinBlock,它可能就是您所需要的。

您还可以创建一个Custom Dataflow Block Type,可以实现您想要达到的目标。

例如,如果您希望5个对象到达,那么在您处理"之前他们,并返回一个单独的对象(我在这里使用expando来展示...),到一个接收器(也应该异步等待):

public sealed class YourCustomBlock : IPropagatorBlock<ExpandoObject, ExpandoObject>
{

    // The target part of the block. coming in
    private readonly ITargetBlock<ExpandoObject> m_target;
    // The source part of the block. going out
    private readonly ISourceBlock<ExpandoObject> m_source;
    // dependency count
    private readonly int _size ;

    // temporary holding area of incoming stuff
    private Queue<ExpandoObject> _queue;

    public YourCustomBlock(int inputs)
    {
      _size = inputs;
      _queue = new Queue<ExpandoObject>(_size);

      var mainWorker= new TransformBlock<ExpandoObject[], ExpandoObject>     (async expandoArray =>
        {
            // Do Your Stuff with expandoArray and then return something
            // ExpandoObject in this example

            await Task.Delay(1000).ConfigureAwait(false); 

            return /*Some ExpandoObject */;
        });

        var head = new ActionBlock<ExpandoObject>(async item =>
        {

            _queue.Enqueue(item);

            if (_queue.Count > _size)
            {
                _queue.Dequeue();  
            }
            // Post when you reach
            // the size
            if (_queue.Count == _size)
            {
                await mainWorker.SendAsync(_queue.ToArray());
                _queue.Clear();
            }
        });

        // expose as a block
        m_source = mainWorker;
        m_target = head;

    }
}

样品使用:

var myBlock = new YourCustomBlock(5);
Task.Run(async () => {
 for (var i=0;i<5;i++) {
    await myBlock.SendAsync(/*SomeExpandoObject*/).ConfigureAwait(false);
 }
});

var results = await myBlock.ReceiveAsync().ConfigureAwait(false);

注意:这还没有经过编译检查,只是这个想法的一个例子。