2012-08-10 17 views
88

所以我最近被告知,我是如何使用我的.ContinueWith for Tasks不是正确的方式来使用它们。我还没有在互联网上找到这个证据,所以我会问你们,看看答案是什么。下面是我如何使用.ContinueWith一个例子:是否prevTask.Wait()建议与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"); 
    }); 
} 
+2

不要使用StartNew http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html – 2016-01-22 21:02:25

回答

113

Ehhh ....我觉得目前的一些答案,失去了一些东西:有例外发生了什么?

如果继续调用Wait,唯一的原因是在继续本身中观察先行者的潜在例外。如果您在Task<T>的情况下访问Result,并且您还手动访问了Exception属性,也会发生同样的情况。 坦率地说,我不会拨打电话Wait或访问Result,因为如果有例外,您需要付出重新提升的代价,这是不必要的开销。相反,你可以检查IsFaulted财产从先行Task。或者,您可以通过链接多个兄弟连续来创建分流工作流,这些连续事件仅基于TaskContinuationOptions.OnlyOnRanToCompletionTaskContinuationOptions.OnlyOnFaulted成功或失败而被触发。

现在,没有必要在延续中观察先行词的例外情况,但是如果例如“第1步”失败,您可能不希望工作流向前进。在这种情况下:指定TaskContinuationOptions.NotOnFaulted给您的ContinueWith调用会阻止继续逻辑甚至无法启动。请注意,如果您自己的延续没有观察到异常,那么等待此整体工作流程完成的人将成为观察它的人。要么他们是Task上游或已经追上自己的延续知道什么时候完成。如果是后者,他们的延续将需要使用前述的观察逻辑。

+2

最后有人给出了正确的答案。 @ Travyguy9请阅读@DrewMarsh回答,并详细了解'TaskContinuationOptions' – Jasper 2012-08-13 06:32:17

+0

良好的通话。谢谢! – Travyguy9 2012-08-13 21:22:35

+2

伟大的答案,我一直在寻找_“请记住,如果你自己的延续没有观察到异常,那么等待这个整体工作流程完成的人就会成为观察它的人。”_一个问题但是,当你的任务没有被等待时,谁是默认的服务员? (找不到这个答案) – 2016-08-22 10:51:52

20

您正确地使用它。

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

来源:Task.ContinueWith Method (Action as MSDN)

不必调用prevTask.Wait()Task.ContinueWith调用似乎是一个奇怪的方式重复不必要的逻辑 - 即做的事情是“超级骗子肯定”,因为你其实不明白是什么有一些代码可以。就像检查一个空值只是为了抛出一个ArgumentNullException无论如何它会抛出。

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

5

MSDNTask.Continuewith

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

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

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

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

+0

是的。我们可以避免Wait()方法。但它只适用于结果任务,例如任务 2017-04-12 07:25:53

+0

Downvoted,因为它没有解决实际问题。它增加了一些价值,但应该是一个评论。 – Sinaesthetic 2017-10-02 21:33:15

1

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

Stephen Cleary的blog post和Stephen Toub的post that he references解释了区别。 this answer也有讨论。

+3

Downvoted,因为它没有解决实际问题。它增加了一些价值,但应该是一个评论。 – Sinaesthetic 2017-10-02 21:33:10

0

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

欲了解更多示例,可以去Chaining Tasks using Continuation Tasks,微软的另一个链接与良好的例子。

相关问题