将多个TransformBlock链接到单个BatchBlock TPL

时间:2017-03-23 18:45:27

标签: c# task-parallel-library tpl-dataflow

我使用TPL Dataflow构建了两个管道:

TransformBlock => TransformBlock => BatchBlock => ....

TransformBlock => BatchBlock => TransformBlock => ....

我想完成

            / => Transform Block => TransformBlock => BatchBlock => ....
BatchBlock /
           \
            \ => Transform Block => BatchBlock => TransformBlock => ....

但是只有第一个管道被执行。

我的代码

batchMediaBlock.LinkTo(pipelineA.FirstBlock, new DataflowLinkOptions {PropagateCompletion = true});
batchMediaBlock.LinkTo(pipelineB.FirstBlock, new DataflowLinkOptions {PropagateCompletion = true});

我该如何做到这一点?

2 个答案:

答案 0 :(得分:1)

BroadcastBlock之后需要BatchBlock。但请注意,完成只会传播到您的TransformBlock之一。请参阅下面的处理完成的部分示例:

using System.Threading.Tasks.Dataflow;

namespace MyDataflow {
    class MyDataflow {

        public void HandlingCompletion() {
            var batchBlock = new BatchBlock<int>(10);
            var broadcastBlock = new BroadcastBlock<int[]>(_ => _);
            var xForm1 = new TransformBlock<int[], int[]>(_ => _);
            var xForm2 = new TransformBlock<int[], int[]>(_ => _);

            batchBlock.LinkTo(broadcastBlock, new DataflowLinkOptions() { PropagateCompletion = true });
            broadcastBlock.LinkTo(xForm1);
            broadcastBlock.LinkTo(xForm1);

            broadcastBlock.Completion.ContinueWith(broadcastBlockCompletionTask => {
                if (!broadcastBlockCompletionTask.IsFaulted) {
                    xForm1.Complete();
                    xForm2.Complete();
                }else {
                    ((IDataflowBlock)xForm1).Fault(broadcastBlockCompletionTask.Exception);
                    ((IDataflowBlock)xForm2).Fault(broadcastBlockCompletionTask.Exception);
                }

            });

            xForm1.Completion.ContinueWith(async _ => {
                try {
                    await xForm2.Completion;
                    //continue passing completion / fault on to rest of pipeline
                } catch  {

                }
            });

        }
    }
}

或者,如果您的管道再次收敛,则可以在继续BroacastBlock后为每个管道分别处理完成。提供的示例将同时完成管道中的每个步骤,同步流动完成。

答案 1 :(得分:1)

默认情况下,TPL数据流中的链接被认为是贪婪的,因此第一个目标始终会收到消息并且将其从上一个块中删除&#39;输出,这就是你的第二个块没有得到任何消息的原因。这种情况可以通过BroadcastBlock<T>解决,

  

确保当前元素在允许元素被覆盖之前广播到任何链接目标。

您还应该注意,此阻止执行克隆消息。

所以你基本上应该在批量阻止后添加广播,但是!你不应该把你的完成从广播块传播给消费者 - 只有第一个才能完成。您应该为@JSteward建议为您的广播添加ContinueWith处理程序。