是否建议prevTask.Wait()与ContinueWith一起使用(来自Tasks库)?


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

Answers:


115

恩。。。我认为当前的一些答案缺少一些内容:例外情况会怎样?

您要Wait在延续中调用的唯一原因是要在延续本身中观察到先例中的潜在异常。如果使用Resulta进行访问,Task<T>并且手动访问该Exception属性,也会发生相同的观察。坦白说,我不会打电话Wait或访问,Result因为如果有异常,您将付出重新筹集的代价,这是不必要的开销。相反,您可以仅检查前一个IsFaulted属性Task。另外,您可以通过链接多个兄弟姐妹连续项来创建分支工作流,这些兄弟连续性仅基于TaskContinuationOptions.OnlyOnRanToCompletion和的成功或失败而触发TaskContinuationOptions.OnlyOnFaulted

现在,没有必要在延续中观察到先例的例外情况,但是,如果“步骤1”失败,您可能不希望工作流程前进。在那种情况下:指定TaskContinuationOptions.NotOnFaulted您的ContinueWith呼叫将阻止继续逻辑甚至触发。

请记住,如果您自己的延续未观察到异常,那么正在等待总体工作流程完成的人员将是观察该异常的人。他们要么是WaitTask上游,要么是依靠自己的延续来知道何时完成。如果是后者,则它们的延续将需要使用上述观察逻辑。


2
最后有人给出了正确的答案。@ Travyguy9请阅读@DrewMarsh的答案,并详细了解TaskContinuationOptions
Jasper

2
很好的答案,我一直在寻找“请记住,如果您自己的延续未发现异常,则正在等待总体工作流程完成的人员将是观察它的人。” 但是有一个问题,当不等待任务时,谁是默认的服务员?(找不到答案)
Thibault D.

20

您正在正确使用它。

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

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

不必调用prevTask.Wait()每个Task.ContinueWith调用似乎是一个奇怪的方式重复不必要的逻辑-即做的事情是“超级骗子肯定”,因为你其实不明白的代码一定位一样。就像检查null只是将其抛出的ArgumentNullException位置都扔了一样。

所以,不,无论谁告诉你这是错误的,并且可能不理解为什么Task.ContinueWith存在。


16

谁告诉你的?

引用MSDN

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

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

您甚至可以自己测试:

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

5

MSDN开始Task.Continuewith

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

我认为第一个示例中的预期工作方式是正确的。



0

通过访问,Task.Result您实际上在执行与task.wait


是。我们可以避免使用Wait()方法。但是它仅适用于结果任务,例如Task <bool>
Alexander Ulmaskulov

拒绝投票,因为它没有解决实际的问题。它增加了一些价值,但应该是评论。
Sinaesthetic

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.