task.continuewith vs c# 中的数据流

Posted

技术标签:

【中文标题】task.continuewith vs c# 中的数据流【英文标题】:task.continuewith vs dataflow in c# 【发布时间】:2016-12-05 04:41:56 【问题描述】:

我已经开始学习TPL Dataflow。我正在努力找出Task.ContinueWith 和数据流之间的区别。以下是具有相同目标的两个示例代码。首先是使用Task.ContinueWith 完成,然后是数据流。 下面是Task.ContinueWith的例子

var tk1 = Task.Run(() =>

    Console.WriteLine("Entered 1st Task");
    Thread.Sleep(3000);
    return 2;
);

tk1.ContinueWith((t) =>

    Console.WriteLine("Entered 2nd Task");
    Thread.Sleep(2000);
    Console.WriteLine(t.Result);
);

tk1.Wait();

以下与数据流相同

var df1 = new TransformBlock<int,int>(t =>

    Console.WriteLine("Entered 1st DF");
    Thread.Sleep(3000);
    return 2;
);

var df2 = new ActionBlock<int>(t =>


    Console.WriteLine("Entered 2nd Task");
    Thread.Sleep(2000);
    Console.WriteLine(t);
);

df1.LinkTo(df2);

df1.Completion.ContinueWith(t =>
df2.Complete());

df1.Post(2);

df2.Completion.Wait();

Task.ContinueWith 看起来比数据流提供的冗长语法简单。任何人都可以请澄清两者之间的区别。

【问题讨论】:

【参考方案1】:

我用来创建复杂的处理管道的数据流,其中流可以分支、合并和循环。 (你在这里展示的例子很简单)

Task.ContinueWith 用在一个更简单的代码中,当流程在一个函数列表中一个接一个地完成时。

【讨论】:

【参考方案2】:

使用您的代码,实际上没有区别。

但是您在数据流方面做错了 - 转换块有什么用,它总是只产生一个独立于输入的结果?

最好做一些处理...

var df1 = new TransformBlock<int,int>(input =>
    
        Console.WriteLine("Entered 1st DF");
        Thread.Sleep(3000);
        return input+1;
    );

...然后您就会看到不同之处:

Task.Run 只会运行一次,但是

df1.Post(2);
df1.Post(5);
df1.Post(27);
df1.Post(-1);

将全部通过您的数据流网格并产生输出。

顺便说一句:使用async/await 而不是Task.ContinueWith 可以使您的代码更简单、更易读。

【讨论】:

【参考方案3】:

您需要完全了解TPL Dataflow 的基础知识,因为现在您正在尝试做TPL Dataflow 管道本身可以轻松完成的事情:

df1.LinkTo(df2, new DataflowLinkOptions  PropagateCompletion = true );

现在您不需要将ContinueWith 用于df1.Completion,但您仍然需要将df1 块(顺便说一下,名字很难看)通知给(惊喜)complete,因为它没有'不知道什么时候完成,与任务相比:

df1.Post(2);
df1.Complete();

调用此方法将拒绝发送到df1块的所有其他消息,并且在它的缓冲区变空后,它将沿着管道传播完成,因此您只需要等待它(同步或异步):

df2.Completion.Wait();
// or
await df2.Completion;

因此,基本上,不同之处在于任务只能运行一次,而块则永远运行,直到您手动完成为止。请注意,您仍然可以继续执行 Completion 块任务:

df2.Completion.ContinueWith(t =>

    // some other logic here
);

【讨论】:

以上是关于task.continuewith vs c# 中的数据流的主要内容,如果未能解决你的问题,请参考以下文章

C# Task 暂停与取消

Task.ContinueWith 和异步(核心 3.1)

在 Task ContinueWith TaskScheduler.FromCurrentSynchronizationContext 的 ShowDialog 中打开表单时,应用程序会冻结

8天玩转并行开发——第四天 同步机制(上)

在单个异步方法中有多个等待的目的

vs2010的c#程序怎么能在VS2003中编译,运行?