[英]Understanding TPL Dataflow, Blocks, and Continuation Tasks
I am working on a project where a need arose that is a perfect scenario for TPL Dataflow. 我正在一个需要满足TPL Dataflow理想情况的项目中工作。 Having relatively limited experience with it (and what I do have was done some time ago), I have been brushing up on it by reading Microsoft's documentation as well as articles I can find online. 由于对它的经验相对有限(并且我之前做过的事情),我一直在阅读Microsoft的文档以及可以在网上找到的文章来进行梳理。
Having done that, I built my code to chain together a series of blocks (mostly TransformBlock
and ending with an ActionBlock
doing something like this: 完成此操作后,我构建了将一系列块链接在一起的代码(主要是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;
Someone in an article (which I can't find) suggested that there should be continuation tasks in the pipeline to mark blocks as complete. 文章中的某人(我找不到)建议管道中应该有继续任务,以将块标记为已完成。 This is the code they provided for that. 这是他们为此提供的代码。
// 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(); }
});
I will admit that I don't fully understand what this code is doing and whether it is even needed. 我承认我不完全了解此代码的功能以及是否需要它。 When I attempt to run this in the code I just wrote, the code hangs on the first ContinueWith
and it never makes it to running the pipeline. 当我尝试在我刚刚编写的代码中运行此代码时,该代码将挂在第一个ContinueWith
,并且永远不会使其运行管道。
I would appreciate additional explanation since I want to get a better understanding of the nuances of what is going on here. 我希望能得到更多的解释,因为我想更好地了解这里发生的细微差别。
All you need to do for a linear pipeline is to PropagateCompletion
. 对于线性管道,您所需要做的就是PropagateCompletion
。 That option propagates Completion
as well as Faults
whose exception is then attached to the final Completion Task
: 该选项会传播“ Completion
”以及“ Faults
,然后将其异常附加到最终“ Completion Task
:
var linkOptions = new DataflowLinkOptions() { PropagateCompletion = true };
block1.LinkTo(block2, linkOptions);
block2.LinkTo(block3, linkOptions);
The continuations are unnecessary. 继续是不必要的。 But if you have pipeline that distributes to multiple blocks you'll need to handle completion and fault propagation yourself as shown here . 但是,如果您有分配给多个块的管道,则需要自己处理完成和错误传播,如下所示 。
the code hangs on the first
ContinueWith
该代码挂在第一个ContinueWith
That happens because you await
the continuation, so if you do that before calling Complete()
then block1
will never complete. 发生这种情况是因为您await
继续,所以如果您在调用Complete()
之前这样做,那么block1
将永远不会完成。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.