繁体   English   中英

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

[英]What happens when you await a failed task

我有一个理论问题要问你。 如果我在另一个任务中等待任务的结果会怎样? 我想知道我当前的系统以后是否可以工作。

一个任务被启动并做一些事情。 在某些时候,该任务可能需要另一个任务来处理当前任务无法自行处理的数据。 所以我使用 await 来确保当前任务不会继续,只要他没有帮助任务的结果。 但是如果 helper 失败了会发生什么? 当前任务会保持锁定状态吗?

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

一个任务被启动并做一些事情。 在某些时候,该任务可能需要另一个任务来处理当前任务无法自行处理的数据。 所以我使用 await 来确保当前任务不会继续,只要他没有帮助任务的结果。 但是如果 helper 失败了会发生什么? 当前任务会保持锁定状态吗?

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 ,任务完成。 DoStuffAsyncawait看到任务已完成时,它会检查其异常并重新引发第一个异常(在这种情况下,只有一个InvalidOperationException )。 它以一种保留异常调用堆栈的方式重新引发它。 这反过来会导致从DoStuffAsync返回的Task以相同的异常完成。

因此,在asyncawait做了一些工作,以确保您可以使用await调用其他方法,并像在同步代码中一样使用try / catch 但大多数时候你不必意识到这一点。

这真的很容易测试。 例如:

[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会抛出一个AggregateException ,而await会抛出Exception

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

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

但是如果 helper 失败了会发生什么? 当前任务会保持锁定状态吗?

首先,我不确定您所说的“锁定”是什么意思。 当您await内部任务时,该任务不会被锁定。 控制权返回给调用方法,直到该内部任务完成。 如果该内部任务失败并且您未能正确处理该异常,则您的父任务也会出错。 您需要确保优雅地处理异常:

var task = 
  Task.Run(async () =>
           {
                 try
                 {
                        await AsyncHelper.DoSomethingAsync();
                 }
                 catch (Exception e)
                 {
                       // Handle exception gracefully
                 }
           });

如果您await父任务,您会注意到从未处理的内部任务传播的内部异常。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM