简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM