等待失败的任务时会发生什么

时间:2014-09-27 19:33:21

标签: c# .net asynchronous task-parallel-library async-await

我有一个理论问题。如果我等待另一个任务中的任务结果会怎样?我想知道我现在的系统是否可以使用。

任务启动并执行一些操作。在某些时候,该任务可能需要另一个任务,以便处理当前任务无法自行处理的数据。所以我使用await确保当前任务不会继续,只要他没有辅助任务的结果。但是如果助手失败会发生什么?当前任务是否会被锁定?

我可以以某种方式避免这种死锁(不改变系统本身 - 任务内部的任务)吗?

3 个答案:

答案 0 :(得分:5)

  

任务启动并执行一些操作。在某些时候,该任务可能需要另一个任务,以便处理当前任务无法自行处理的数据。所以我使用await确保当前任务不会继续,只要他没有辅助任务的结果。但是如果助手失败会发生什么?当前任务是否会被锁定?

asyncawait背后的核心思想是异步代码与同步代码的工作方式大致相同。

所以,如果你有这样的同步代码:

void HelperMethod()
{
  throw new InvalidOperationException("test");
}

void DoStuff()
{
  HelperMethod();
}

然后您希望DoStuff从辅助方法传播InvalidOperationException。同样,异步代码会发生什么:

async Task HelperMethodAsync()
{
    throw new InvalidOperationException("test");
}

async Task DoStuffAsync()
{
    await HelperMethodAsync();
}

也就是说,DoStuffAsync也会传播InvalidOperationException

现在,它并没有以相同的方式完全 ,因为它必须是异步的,但一般的想法是所有的控制流程,例如try / catchfor循环等,所有"只是工作"对于异步代码非常类似于同步代码。

实际正在进行的是当HelperMethodInvalidOperationException结尾时,异常会被捕获并放在返回的Task上,并完成任务。当await DoStuffAsync看到任务已完成时,它会检查其异常并重新引发第一个(在这种情况下,只有一个InvalidOperationException)。它以一种在异常上保留调用堆栈的方式重新引发它。这反过来导致从Task返回的DoStuffAsync完成同样的异常。

因此,在asyncawait下,我们正在做一些工作,以确保您可以使用await调用其他方法并使用try / {{ 1}}与同步代码中的方式相同。但大部分时间你都不必意识到这一点。

答案 1 :(得分:2)

  

如果我等待另一个任务中的任务结果会怎样?

如果await Task.Result(意味着它有awaitable方法),则您只能GetAwaiter await。这种情况很少发生。我假设你在内部任务上的意思是await

  

但是如果助手失败会发生什么?当前任务是否会被锁定?

首先,我不确定你的意思"锁定"。在var task = Task.Run(async () => { try { await AsyncHelper.DoSomethingAsync(); } catch (Exception e) { // Handle exception gracefully } }); 执行内部任务时,任务未被锁定。控制将返回到调用方法,直到内部任务完成。如果该内部任务失败并且您未能正确处理该异常,那么您的父任务也将出错。您需要确保优雅地处理异常:

await

如果你在父任务上{{1}},你会注意到未处理的内部任务传播的内部异常。

  

我可以以某种方式避免这种僵局吗?

我认为没有理由为什么你的代码在这种特定情况下应该死锁。不知道为什么这会让你担心。

答案 2 :(得分:1)

测试真的很容易。例如:

[TestMethod, ExpectedException(typeof(Exception))]
public async Task DoFaultedTaskThrowOnAwait()
{
  var task = Task.Factory.StartNew(() => { throw new Exception("Error 42"); });
  await task;
}

[TestMethod, ExpectedException(typeof(AggregateException))]
public void DoFaultedTaskThrowOnWait()
{
  var task = Task.Factory.StartNew(() => { throw new Exception("Error 42"); });
  task.Wait();
}

两个测试均通过,请注意Wait抛出AggregateExceptionawait抛出Exception