所以我最近被告知我如何使用我的.ContinueWith for Tasks并不是使用它们的正确方法。我还没有在互联网上找到这方面的证据,所以我会问你们,看看答案是什么。这是我如何使用的例子.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");
});
}
嗯....我认为目前的一些答案缺少一些东西:例外会发生什么?
你继续称之为Wait
的唯一原因是观察延续本身中前因的潜在例外。如果你在Result
的情况下访问Task<T>
,并且你手动访问Exception
属性,也会发生同样的观察。坦率地说,我不会打电话给Wait
或访问Result
,因为如果有例外,你将支付重新筹集它的价格,这是不必要的开销。相反,你可以检查先前IsFaulted
的Task
属性。或者,您可以通过链接多个兄弟连续来创建分叉工作流,这些连续仅基于TaskContinuationOptions.OnlyOnRanToCompletion
和TaskContinuationOptions.OnlyOnFaulted
的成功或失败而触发。
现在,没有必要在延续中观察前提的例外情况,但是如果“步骤1”失败,您可能不希望您的工作流程向前推进。在这种情况下:将TaskContinuationOptions.NotOnFaulted
指定给你的ContinueWith
调用会阻止连续逻辑永远触发。
请记住,如果您自己的延续没有观察到异常,那么等待整个工作流程完成的人将成为观察它的人。他们要么在上游的Wait
上进行Task
ing,要么已经在他们自己的继续下去了解它何时完成。如果是后者,他们的继续将需要使用上述观察逻辑。
您正确使用它。
创建在目标任务完成时异步执行的延续。
资料来源:Task.ContinueWith Method (Action as MSDN)
必须在每个prevTask.Wait()
调用中调用Task.ContinueWith
似乎是一种奇怪的方式来重复不必要的逻辑 - 即做一些“超级确定”,因为你实际上不明白某些代码的作用。就像检查一个null只是为了抛出一个ArgumentNullException
它无论如何都会抛出。
所以,不,谁告诉你这是错的,可能不明白为什么Task.ContinueWith
存在。
谁告诉你的?
引用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");
});
来自MSDN的Task.Continuewith
在当前任务完成之前,将不会安排返回的任务执行。如果不满足通过continuationOptions参数指定的条件,则将取消继续任务而不是已安排。
我认为你希望它在第一个例子中起作用的方式是正确的方法。
您可能还想考虑使用Task.Run而不是Task.Factory.StartNew。
Stephen Cleary的blog post和Stephen Toub的post that he references解释了这些差异。在this answer也有讨论。
通过访问Task.Result
,你实际上正在做与task.wait
类似的逻辑
我将重申许多人已经说过的话,prevTask.Wait()
是不必要的。
有关更多示例,可以访问Chaining Tasks using Continuation Tasks,这是Microsoft提供的另一个链接示例。