任务中没有立即中断的异常
本文关键字:中断 异常 任务 | 更新日期: 2023-09-27 18:02:26
一些伪代码来说明我的问题:
public async Task DoSomethingAsync()
{
try
{
var task1 = DoThisAsync(); // throws exception
var task2 = DoThatAsync();
await task1.Then(t => Handle(t));
await task2.Then(t => Handle(t));
}
catch (AggregateException)
{
Console.WriteLine("Whatnow?");
}
}
And Then的定义如下:
// from https://gist.github.com/rizal-almashoor/2818038
public static Task Then(this Task task, Action<Task> next)
{
var tcs = new TaskCompletionSource<AsyncVoid>();
task.ContinueWith(t=>
{
if (t.IsFaulted)
tcs.TrySetException(t.Exception); // continuing task1 this line only gets hit
// after DoThatAsync() is completed??
else
{
try
{
next(t);
tcs.TrySetResult(default(AsyncVoid));
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
});
return tcs.Task;
}
所以我的问题是,由于某种原因,即使DoThisAsync()抛出异常相当早,我没有看到"现在是什么",直到DoThatAsync()完成。这不是确切的代码,我试图简化,不浪费你的时间。如果这里没有解释这种行为,请告诉我,我会添加更多细节。
编辑
对于这个问题的目的,我们可以想象DoThisAsync()和DoThatAsync()是异步方法,基本上做以下事情:
DoThisAsync:
Thread.Sleep(30000); // wait a short perioud of time
throw new Exception(); // and throw an exception
DoThatAsnyc:
Thread.Sleep(240000); // wait a long period of time
假设您的DoThisAsync
启动了一个新任务,并且该任务的操作是引发异常的原因—是这样吗?
在这种情况下,异常存储在Task中。除非调用. wait或. result等触发器方法,否则异常不会被重新抛出。当你await
从Then
返回的任务时,它会导致该任务的异常被重新抛出。
基于你的编辑显示DoThisAsync:当返回Task的async
标记方法导致异常时,该异常将存储在Task中(而不是允许它传播)。如果你要删除async
关键字,我希望在DoThisAsync被调用时发生异常。
来自Stephen Toub的Async/Await常见问题解答:http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx:
"async"关键字应用于方法时做什么?
当你用" async "关键字标记一个方法时,你实际上是在告诉编译器两件事:
- 你告诉编译器,你希望能够在方法中使用" await "关键字(当且仅当它所在的方法或lambda被标记为async时,你可以使用await关键字)。在这样做时,您告诉编译器使用状态机编译该方法,这样该方法将能够挂起,然后在等待点异步恢复。
- 你告诉编译器"提升"方法的结果或任何可能发生的异常到返回类型。对于返回Task或Task的方法,这意味着在方法中未处理的任何返回值或异常都存储到结果任务中。对于返回void的方法,这意味着任何异常都会通过方法初始调用时当前的"SynchronizationContext"传播到调用者的上下文中。