了解TPL数据流,块和继续任务

时间:2017-12-13 19:46:25

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

我正在开发一个需要的项目,这是TPL Dataflow的完美场景。对它的经验相对有限(以及我之前做过的事情),我一直在阅读微软的文档以及我在网上找到的文章。

完成后,我构建了我的代码,将一系列块(大多数为TransformBlock并以ActionBlock结尾,并执行以下操作:

var block1 = new TransformBlock<T, U>(async input => {});
var block2 = new TransformBlock<U, V>(async input => {});
var block3 = new ActionBlock<V>(async input => {});

block1.LinkTo(block2);
block2.LinkTo(block3);

foreach(var item in items)
{
   await block1.SendAsync(item);
}
block1.Complete();
await block3.Completion;

文章中的某人(我找不到)建议管道中应该有继续任务来将块标记为完整。这是他们为此提供的代码。

// Create the continuation tasks in the pipeline that marks each block as complete.
await block1.Completion.ContinueWith(t =>
{
    if (t.IsFaulted) { ((IDataflowBlock)block2).Fault(t.Exception); }
    else { block2.Complete(); }
});
await block2.Completion.ContinueWith(t =>
{
    if (t.IsFaulted) { ((IDataflowBlock)block3).Fault(t.Exception); }
    else { block3.Complete(); }
});

我承认我并不完全理解这段代码在做什么以及是否需要它。当我尝试在我刚写的代码中运行它时,代码挂起在第一个ContinueWith上,它永远不会使它运行管道。

我希望得到更多解释,因为我希望更好地了解这里发生的细微差别。

1 个答案:

答案 0 :(得分:2)

线性管道的所有工作都需要PropagateCompletion。该选项会传播Completion以及Faults,然后将其例外附加到最终Completion Task

var linkOptions = new DataflowLinkOptions() { PropagateCompletion = true };
block1.LinkTo(block2, linkOptions);
block2.LinkTo(block3, linkOptions);

延续是不必要的。但是如果你有分配到多个块的管道,你需要自己处理完成和故障传播as shown here

  

代码挂在第一个ContinueWith

这是因为你await延续,所以如果你在调用Complete()之前这样做,那么block1永远不会完成。