我正在开发一个需要的项目,这是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
上,它永远不会使它运行管道。
我希望得到更多解释,因为我希望更好地了解这里发生的细微差别。
答案 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
永远不会完成。