适当的方式使用.ContinueWith任务

所以我最近被告知,我是如何使用我的.ContinueWith for Tasks不是正确的方式来使用它们。 我还没有在互联网上find这个证据,所以我会问你们,看看答案是什么。 这里是我如何使用.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"); }); } 

呃……我认为目前的一些答案是缺less的东西:exception会发生什么?

你将继续叫做“ Wait ”的唯一原因是在继续本身中观察先前的潜在例外。 如果您在Task<T>的情况下访问了“ Result ,而且您还手动访问了“ Exception属性,也会发生同样的Exception 。 坦率地说,我不会叫Wait或访问Result因为如果有例外,你会付出重新抬高的代价,这是不必要的开销。 相反,您可以从前面的Task检查IsFaulted属性。 或者,您可以通过链接多个同级连续创build分叉工作stream,这些同级连续只能根据TaskContinuationOptions.OnlyOnRanToCompletionTaskContinuationOptions.OnlyOnFaulted成功或失败进行触发。

现在,没有必要观察前面的例外情况,但是如果“步骤1”失败,则可能不希望工作stream向前进。 在这种情况下:指定TaskContinuationOptions.NotOnFaulted到你的ContinueWith调用将阻止继续逻辑甚至不能发射。

请记住,如果你自己的延续没有观察到exception,那么等待这个整体工作stream程完成的人就会成为观察它的人。 他们要么Wait上游的Task要么Wait自己的继续来知道什么时候完成。 如果是后者,他们的延续将需要使用前述的观察逻辑。

您正确使用它。

创build一个在目标任务完成时asynchronous执行的延续

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

必须在每个Task.ContinueWith调用中调用prevTask.Wait() ,似乎是重复不必要的逻辑的一种奇怪的方式,也就是说,做一些事情是“超级确定的”,因为你实际上不知道某个代码是干什么的。 就像检查null一样,只是抛出一个ArgumentNullException ,它已经抛出了。

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

谁告诉你的?

引用MSDN :

创build一个在目标任务完成时asynchronous执行的延续。

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

你甚至可以自己testing一下:

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

从MSDN上的Task.Continuewith

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

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

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

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

斯蒂芬·克莱里的博客文章和斯蒂芬·托比的post,他引用解释的差异。 这个答案也有讨论。