【问题标题】:Exception thrown in async method is not caught - why?未捕获异步方法中引发的异常 - 为什么?
【发布时间】:2021-12-26 04:10:09
【问题描述】:

我很难理解 async/await 在各种非快乐路径情况下的工作原理。例如,我有以下代码:

    class Program
    {
        static void Main(string[] args)
        {
            Do();
            Console.ReadLine();
        }

        private static void Do()
        {
            TaskScheduler.UnobservedTaskException += (s, e) =>
            {
                Console.WriteLine($"Unobserved Exception : {e.Exception.Message}");
                e.SetObserved();
            };
            
            try
            {                
                ThrowsAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Caught in try/catch  : {ex.Message}");
            }
        }

        private static async Task ThrowsAsync()
        {    
            Console.WriteLine("Throwing");
            throw new Exception("FAILURE");
        }
    }

有两点我不明白:

  1. ThrowsAsync 方法是异步的,但是它不包含任何await。我假设在这种情况下,该方法将像“正常”同步方法一样执行。但是,它抛出的异常永远不会在 catch 块中捕获。
  2. 试图以某种方式捕获异常,我为TaskScheduler.UnobservedTaskException 添加了处理程序。但是,它永远不会被执行。这是为什么呢?

我知道如果我等待ThrowsAsync,就会捕获异常。不过,我正在尝试更好地了解它的工作原理。

我正在使用 .NET 5 和基于 Linux 的操作系统运行该代码。

【问题讨论】:

  • 第二个this可以解释一下。对于第一个 ThrowsAsync 是异步的并返回一个 Task 所以在等待之前它不应该抛出。
  • 也适用于第一点 - this.
  • @GuruStron 关于UnobservedTaskException。我试图遵循链接 SO 中的建议。我在Do 方法的末尾添加了以下内容:Console.WriteLine("GC"); Thread.Sleep(100); GC.Collect(); GC.WaitForPendingFinalizers();。它没有改变任何东西。我看到控制台中打印了“GC”,仅此而已。
  • @Loreno 你可以和this article 一起去硬核,或者阅读斯蒂芬·克利里的博客和书籍(博客之前链接过)。

标签: c# .net asynchronous exception async-await


【解决方案1】:
  1. 正如 Stephen Cleary 所描述的例如in this blog post - async 方法的状态机将从您的代码中捕获异常并将它们放置在返回的任务中,即方法调用不会抛出,您将能够捕获异常如果await 结果。

  2. 至于TaskScheduler.UnobservedTaskException - 查看this answer 并确保在Release 模式下运行代码。

【讨论】:

    猜你喜欢
    • 2011-07-19
    • 2012-06-05
    • 2015-04-22
    • 1970-01-01
    • 2014-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多