我应该使用常规任务还是继续任务?

时间:2014-08-29 16:31:22

标签: c# asynchronous compare task-parallel-library task

假设定义了以下方法:

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函数中引发异常会发生什么?它是否会被吞噬,或者是否保证每一个潜在的例外都被提升到一个可以处理的区域?

1 个答案:

答案 0 :(得分:2)

在你的第一种情况下,lambda不需要async。没有必要await任务。您可以使用Result,因为您知道该任务已在该时间点完成。

对于第二个示例,您正在调度线程池线程以执行状态机的创建,该状态机将仅安排在任务完成时运行的某些代码。根本没有必要这样做。 Task.Run在这里没有添加任何内容。

方法本身很可能应该是async方法:

private async Task MyFunction() {
    var result = await DoStuffAsync();
    // do stuff with result
}

所有这一切都说,虽然你的两个解决方案都有很多多余的工作,但两者都会将基础工作中的异常传播到每个操作计算的任务中(尽管你不会在第一个例子中的任何地方存储该任务) ,所以你无法检查那个任务是否有故障。