假设定义了以下方法:
Task<TResult> DoStuffAsync()
{
// ...
}
考虑以下代码(代码段1):
void MyFunction()
{
Task<TResult> task = DoStuffAsync();
task.ContinueWith(async () => {
TResult result = await task;
// do stuff with result
});
// poll `task` status...
}
与以下代码(代码段2)相比:
void MyFunction()
{
Task<TResult> task = DoStuffAsync();
Task.Run(async () => {
TResult result = await task;
// do stuff with result
});
// poll `task` status...
}
(注意我不关心lambda函数的状态(即发即忘)。但如果它引发任何异常,我做小心。)
两个选项之间的第一个区别似乎很清楚:在(代码段1)中,lambda中的代码只会在 DoStuffAsync()
完成后开始执行,而在(代码段2)中lambda中的代码将尝试立即开始执行,并在DoStuffAsync()
完成后继续。
但是,除了这种差异之外,您应该何时使用ContinueWith
,何时应该使用Task.Run
?如果在DoStuffAsync()
或lambda函数中引发异常会发生什么?它是否会被吞噬,或者是否保证每一个潜在的例外都被提升到一个可以处理的区域?
答案 0 :(得分:2)
在你的第一种情况下,lambda不需要async
。没有必要await
任务。您可以使用Result
,因为您知道该任务已在该时间点完成。
对于第二个示例,您正在调度线程池线程以执行状态机的创建,该状态机将仅安排在任务完成时运行的某些代码。根本没有必要这样做。 Task.Run
在这里没有添加任何内容。
方法本身很可能应该是async
方法:
private async Task MyFunction() {
var result = await DoStuffAsync();
// do stuff with result
}
所有这一切都说,虽然你的两个解决方案都有很多多余的工作,但两者都会将基础工作中的异常传播到每个操作计算的任务中(尽管你不会在第一个例子中的任何地方存储该任务) ,所以你无法检查那个任务是否有故障。