在任务中抛出异常 - “await”与等待()

发布于 2024-12-03 05:33:25 字数 686 浏览 1 评论 0 原文

static async void Main(string[] args)
{
    Task t = new Task(() => { throw new Exception(); });

    try
    {                
        t.Start();
        t.Wait();                
    }
    catch (AggregateException e)
    {
        // When waiting on the task, an AggregateException is thrown.
    }

    try
    {                
        t.Start();
        await t;
    }
    catch (Exception e)
    {
        // When awating on the task, the exception itself is thrown.  
        // in this case a regular Exception.
    }           
}

在 TPL 中,当在任务中抛出异常时,它会被 AggregateException 包装起来。
但使用 await 关键字时,不会发生同样的情况。
这种行为的解释是什么?

static async void Main(string[] args)
{
    Task t = new Task(() => { throw new Exception(); });

    try
    {                
        t.Start();
        t.Wait();                
    }
    catch (AggregateException e)
    {
        // When waiting on the task, an AggregateException is thrown.
    }

    try
    {                
        t.Start();
        await t;
    }
    catch (Exception e)
    {
        // When awating on the task, the exception itself is thrown.  
        // in this case a regular Exception.
    }           
}

In TPL, When throwing an exception inside a Task, it's wrapped with an AggregateException.
But the same is not happening when using the await keyword.
What is the explanation for that behavior ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雄赳赳气昂昂 2024-12-10 05:33:25

目标是使其看起来/表现得像同步版本。 Jon Skeet 在他的 Eduasync 系列中对此做了很好的解释,特别是这篇文章:

http://codeblog.jonskeet.uk/2011/06/22/eduasync-part-11-more-sophisticated-but-lossy-exception-handling/

The goal is to make it look/act like the synchronous version. Jon Skeet does a great job explaining this in his Eduasync series, specifically this post:

http://codeblog.jonskeet.uk/2011/06/22/eduasync-part-11-more-sophisticated-but-lossy-exception-handling/

相对绾红妆 2024-12-10 05:33:25

在 TPL 中使用 AggregateException 是因为等待操作中可以有多个任务(任务可以附加子任务),因此其中许多任务都可以抛出异常。请查看此处的子任务中的异常部分:

https://msdn.microsoft.com/ru-ru/library/dd997417(v=vs.110).aspx

await 你总是只有一项任务。

另请参阅 https://msdn.microsoft.com /ru-ru/library/dd997415(v=vs.110).aspx

In TPL AggregateException is used because you can have multiple tasks in wait operation (task can have child tasks attached), so many of them can throw exceptions. Look at Exceptions in child tasks section here:

https://msdn.microsoft.com/ru-ru/library/dd997417(v=vs.110).aspx

In await you always have just one task.

See also https://msdn.microsoft.com/ru-ru/library/dd997415(v=vs.110).aspx

南烟 2024-12-10 05:33:25

Stephen Toub 详细解释了为什么 Task.Wait() 和 wait 之间的异常类型不同:

.NET 4.5 中的任务异常处理

在 .NET 4 中设计 Task.Wait 时,我们选择始终传播
总计的。该决定受到不覆盖的需要的影响
详细信息,而且还包括当时任务的主要用例,
fork/join 并行性,其中可能出现多个异常
很常见。

虽然与高级别的 Task.Wait 类似(即前进进度
直到任务完成才进行),“等待任务”代表一个非常
不同的主要场景集。而不是被用于
fork/join 并行性,“等待任务”最常见的用法是
获取一段连续的、同步的代码并将其转换为
顺序的、异步的代码段。在代码中的地方
您执行同步操作,将其替换为
由任务表示的异步操作并“等待”它。像这样,
虽然您当然可以使用await 进行fork/join 操作(例如
利用 Task.WhenAll),这不是 80% 的情况。此外,.NET 4.5
看到介绍
System.Runtime.ExceptionServices.ExceptionDispatchInfo,它解决了
允许跨线程封送异常的问题
不会丢失堆栈跟踪和 Watson 存储桶等异常详细信息。
给定一个异常对象,您将其传递给
ExceptionDispatchInfo.Create,返回一个ExceptionDispatchInfo
包含对 Exception 对象的引用和副本的对象
其详细信息。当需要抛出异常时,
ExceptionDispatchInfo的Throw方法用于恢复内容
异常并抛出它而不丢失原始信息
(当前的调用堆栈信息附加到已经存在的内容上
存储在异常中)。

鉴于此,再次可以选择始终抛出第一个
或者总是抛出一个聚合,对于“等待”,我们选择总是抛出
第一个。但这并不意味着您无权访问
相同的细节。在所有情况下,任务的 Exception 属性仍然
返回包含所有异常的 AggregateException,因此
你可以接住扔出的任何一个并回去咨询
需要时出现 Task.Exception。是的,这会导致之间的差异
在“task.Wait()”和“await”之间切换时的异常行为
任务”,但我们认为这是两害相权取其轻。

Here is a good explanation in details, by Stephen Toub, why there is a difference in exception type between Task.Wait() and await:

Task Exception Handling in .NET 4.5

When designing Task.Wait in .NET 4, we chose always propagating an
aggregate. That decision was influenced by the need to not overwrite
details, but also by the primary use case for tasks at the time, that
of fork/join parallelism, where the potential for multiple exceptions
is quite common.

While similar to Task.Wait at a high level (i.e. forward progress
isn’t made until the task completes), “await task” represents a very
different primary set of scenarios. Rather than being used for
fork/join parallelism, the most common usage of “await task” is in
taking a sequential, synchronous piece of code and turning it into a
sequential, asynchronous piece of code. In places in your code where
you perform a synchronous operation, you replace it with an
asynchronous operation represented by a task and “await” it. As such,
while you can certainly use await for fork/join operations (e.g.
utilizing Task.WhenAll), it’s not the 80% case. Further, .NET 4.5
sees the introduction of
System.Runtime.ExceptionServices.ExceptionDispatchInfo, which solves
the problem of allowing you to marshal exceptions across threads
without losing exception details like stack trace and Watson buckets.
Given an exception object, you pass it to
ExceptionDispatchInfo.Create, which returns an ExceptionDispatchInfo
object that contains a reference to the Exception object and a copy of
the its details. When it’s time to throw the exception, the
ExceptionDispatchInfo’s Throw method is used to restore the contents
of the exception and throw it without losing the original information
(the current call stack information is appended to what’s already
stored in the Exception).

Given that, and again having the choice of always throwing the first
or always throwing an aggregate, for “await” we opt to always throw
the first. This doesn’t mean, though, that you don’t have access to
the same details. In all cases, the Task’s Exception property still
returns an AggregateException that contains all of the exceptions, so
you can catch whichever is thrown and go back to consult
Task.Exception when needed. Yes, this leads to a discrepancy between
exception behavior when switching between “task.Wait()” and “await
task”, but we’ve viewed that as the significant lesser of two evils.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文