88

所以最近有人告诉我,我如何使用 .ContinueWith 来处理任务并不是使用它们的正确方法。我还没有在互联网上找到这方面的证据,所以我会问你们,看看答案是什么。这是我如何使用 .ContinueWith 的示例:

public Task DoSomething()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 2");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 3");
    });
}

现在我知道这是一个简单的例子,它会运行得非常快,但只是假设每个任务都做了一些更长的操作。所以,我被告知在.ContinueWith 中,你需要说prevTask.Wait(); 否则你可以在上一个任务完成之前完成工作。这甚至可能吗?我假设我的第二个和第三个任务只有在他们之前的任务完成后才会运行。

我被告知如何编写代码:

public Task DoSomething()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
    })
    .ContinueWith((prevTask) =>
    {
        prevTask.Wait();
        Console.WriteLine("Step 2");
    })
    .ContinueWith((prevTask) =>
    {
        prevTask.Wait();
        Console.WriteLine("Step 3");
    });
}
4

7 回答 7

116

Ehhh ....我认为当前的一些答案缺少一些东西:异常会发生什么?

您调用Wait延续的唯一原因是观察延续本身中前件的潜在异常。Result如果您在 a 的情况下访问Task<T>并且如果您手动访问该Exception属性,也会发生相同的观察。坦率地说,我不会打电话Wait或访问Result,因为如果出现异常,您将付出重新提高它的代价,这是不必要的开销。相反,您可以只检查前件的IsFaulted属性Task。或者,您可以通过链接多个兄弟延续来创建分叉工作流,这些延续仅基于成功或失败使用TaskContinuationOptions.OnlyOnRanToCompletionand触发TaskContinuationOptions.OnlyOnFaulted

现在,没有必要在 continuation 中观察前件的异常,但如果“步骤 1”失败,您可能不希望您的工作流程继续前进。在这种情况下:指定TaskContinuationOptions.NotOnFaulted您的ContinueWith调用将阻止延续逻辑甚至触发。

请记住,如果您自己的延续没有观察到异常,那么等待整个工作流程完成的人将是观察它的人。他们要么WaitTask上游进行,要么已经在自己的延续上知道它何时完成。如果是后者,他们的延续就需要使用前面提到的观察逻辑。

于 2012-08-10T17:56:21.963 回答
20

您正在正确使用它。

创建一个在目标任务完成时异步执行的延续。

来源:Task.ContinueWith 方法(作为 MSDN 的操作)

prevTask.Wait()每次调用都必须Task.ContinueWith调用似乎是一种重复不必要逻辑的奇怪方式——即做一些“超级可靠”的事情,因为你实际上不了解某段代码的作用。就像检查 null 只是为了抛出一个ArgumentNullException无论如何都会被抛出的地方。

所以,不,谁告诉你这是错误的,可能不明白为什么Task.ContinueWith存在。

于 2012-08-10T15:32:28.917 回答
16

谁告诉你的?

引用MSDN

创建一个在目标任务完成时异步执行的延续。

另外,如果不等待上一个任务完成,继续的目的是什么?

你甚至可以自己测试它:

Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
        Thread.Sleep(2000);
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("I waited step 1 to be completed!");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 3");
    });
于 2012-08-10T15:34:53.207 回答
5

MSDNTask.Continuewith

在当前任务完成之前,不会安排返回的任务执行。如果不满足通过 continuationOptions 参数指定的条件,则继续任务将被取消而不是计划。

我认为您期望它在第一个示例中的工作方式是正确的方式。

于 2012-08-10T15:32:44.990 回答
2

您可能还想考虑使用 Task.Run 而不是 Task.Factory.StartNew。

Stephen Cleary 的博客文章和他引用的 Stephen Toub 的文章解释了这些差异。这个答案中也有讨论。

于 2017-01-17T00:01:24.797 回答
0

通过访问Task.Result你实际上是在做类似的逻辑task.wait

于 2015-09-17T15:34:53.137 回答
0

我将重申许多人已经说过的话,prevTask.Wait() 是不必要的

有关更多示例,可以转到使用连续任务链接任务,这是 Microsoft 提供的另一个链接,其中包含很好的示例。

于 2018-02-18T08:29:20.530 回答