task.coninuewithvs c#中的数据流

本文关键字:数据流 coninuewithvs task | 更新日期: 2023-09-27 17:59:23

我已经开始学习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看起来比数据流提供的冗长语法更简单。谁能澄清一下两者之间的区别吗。

task.coninuewithvs c#中的数据流

数据流我用来创建一个compleax进程pipleins,流可以在其中分支、合并和循环。(你在这里展示的例子很简单)

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

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

但对于数据流来说,你做得不对——变换块有什么用,它总是只产生一个独立于输入的结果?

最好做一些处理。。。

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);

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

BTW:使用async/await而不是Task.ContinueWith可以使代码更简单、更可读。

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

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

现在,df1.Completion不需要使用ContinueWith,但您仍然需要通知df1块(顺便说一句,命名很难看)(意外)完成,因为它不知道何时完成,与task:相比

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

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

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

所以,基本上,区别在于任务只能运行一次,而块永远运行,直到你手动完成它。注意,你仍然可以继续块的Completion任务:

df2.Completion.ContinueWith(t =>
{
    // some other logic here
});