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

C# 等待失败的任务时会发生什么,c#,.net,asynchronous,task-parallel-library,async-await,C#,.net,Asynchronous,Task Parallel Library,Async Await,我有一个理论问题要问你。如果我在另一个任务中等待一个任务的结果,会发生什么?我想知道我现在的系统以后是否还能工作 启动一个任务并做一些事情。在某些情况下,该任务可能需要另一个任务来处理当前任务本身无法处理的数据。所以我使用wait来确保当前任务不会继续,只要他没有助手任务的结果。但是如果助手失败了怎么办?当前任务将保持锁定状态吗 我能以某种方式避免这种死锁吗(不改变系统本身-任务内的任务)?测试非常容易。例如: [TestMethod, ExpectedException(typeof(Exce

我有一个理论问题要问你。如果我在另一个任务中等待一个任务的结果,会发生什么?我想知道我现在的系统以后是否还能工作

启动一个任务并做一些事情。在某些情况下,该任务可能需要另一个任务来处理当前任务本身无法处理的数据。所以我使用wait来确保当前任务不会继续,只要他没有助手任务的结果。但是如果助手失败了怎么办?当前任务将保持锁定状态吗


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

测试非常容易。例如:

[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
抛出
aggregateeexception
,而
Wait
抛出
异常

如果我在另一个任务中等待一个任务的结果,会发生什么

如果任务是
可等待的
(意味着它有一个
获取等待者
方法),则只能
等待
任务。结果
。这种情况很少发生。我猜你的意思是等待一项内部任务

但是如果助手失败了怎么办?当前任务将保持锁定状态吗

首先,我不知道你说的“锁定”是什么意思。当您等待内部任务时,任务未锁定。控件被退回到调用方法,直到该内部任务完成。如果该内部任务失败,并且您未能正确处理该异常,则您的父任务也将失败。您需要确保优雅地处理异常:

var task = 
  Task.Run(async () =>
           {
                 try
                 {
                        await AsyncHelper.DoSomethingAsync();
                 }
                 catch (Exception e)
                 {
                       // Handle exception gracefully
                 }
           });
如果您在父任务上等待,您将注意到未处理的内部任务正在传播内部异常

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

我看不出您的代码在这种特定情况下会死锁的原因。不知道为什么这会让你担心

启动一个任务并做一些事情。在某些情况下,该任务可能需要另一个任务来处理当前任务本身无法处理的数据。所以我使用wait来确保当前任务不会继续,只要他没有助手任务的结果。但是如果助手失败了怎么办?当前任务将保持锁定状态吗

async
await
背后的核心思想是异步代码的工作原理与同步代码几乎相同

因此,如果您有如下同步代码:

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

void DoStuff()
{
  HelperMethod();
}
然后您将期望
DoStuff
从helper方法传播
invalidoOperationException
。类似地,异步代码也是如此:

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

async Task DoStuffAsync()
{
    await HelperMethodAsync();
}
也就是说,
dostufasync
也会传播
invalidoOperationException

当然,它的工作方式并不完全相同,因为它必须是异步的,但是一般的想法是,所有的控制流,比如
try
/
catch
for
循环,等等,都对异步代码“起作用”,与同步代码非常类似

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


因此,在封面下,
async
await
正在做一些工作,以确保您可以使用
await
调用其他方法,并使用
try
/
catch
,方法与在同步代码中相同。但是大多数时候你不必意识到这一点。

编写一个简单的测试代码并观察结果如何?你不能等待结果,你可以等待任务。如果失败了,它会抛出一个异常,我可以编写测试代码,但这比在这里询问要长得多。回答这个问题不应该太费劲:)否则我很抱歉。对不起,是我的错。当然,我的意思是等待任务。所以理论上,如果等待的任务失败,“等待”会抛出一个异常?谢谢你的解释。与此相关的另一个问题是:当我调用“task.Result”(或者task.Wait())时,它真的被锁定了,不是吗?这是一个可能的死锁源,还是安全的?我相信你指的是。真是巧合。我真的有这种情况,甚至不是我最初担心的问题。但是仍然非常有用,因为这个场景正好发生在我认为可能发生的位置:我已经异步运行的方法(该方法本身不是异步的,但它在第二个线程上运行)创建另一个任务,并且必须等待它完成。同样的问题:-/所以我真的必须重新设计我的整个系统,以便有异步方法可以等待这些任务。。。