如何使用异步等待处理多个异常

Posted

技术标签:

【中文标题】如何使用异步等待处理多个异常【英文标题】:How to handle multiple exceptions with async await 【发布时间】:2015-09-01 20:46:49 【问题描述】:

我遵循 Microsoft 在此处指定的模式。 https://msdn.microsoft.com/en-us/library/hh191443.aspx

本文介绍了如何使用 await 开发异步代码。但是,他们没有谈论在 await 返回之前出现异常时会发生什么。

在下面的示例中,外部异常结束了父线程,并且任务没有线程可以返回。我该如何处理这种情况?

class Program
    
        private static void Main(string[] args)
        
            CallAsync();
            Console.ReadKey();
        

        public static async void CallAsync()
        
            var task = CallExceptionAsync();
            ThrowException("Outside");
            await task;
        

        public static Task CallExceptionAsync()
        
            return Task.Run(() =>
            
                ThrowException("Inside");
            );

        

        public static void ThrowException(string msg)
        
            throw new Exception(msg);
                
    

【问题讨论】:

【参考方案1】:

您必须准备好处理可能已渗透回主线程的异常,方法是用 try/catch 包围该调用。在这种情况下,您应该收到一个 AggregateException,它包含您启动的异步线程中的一个或多个异常。

【讨论】:

我有点误读了你的例子。我所说的对于您正在启动的第二个线程是正确的,但是您也在主线程级别引发了异常。你想说啥?如果您没有针对该主线程异常的 catch 块,它将被终止(或被更高层的其他代码捕获)。你是问如果第一个线程在它之前终止,第二个线程会发生什么? 我的例子是一个愚蠢的例子。我的实际代码更复杂,我能够在这里复制相同的行为。在我的原始代码中,我正在调用 Web 服务,同时也保存到数据库中。两者都抛出异常。我可以在这里复制一个不太复杂的例子。它是否在 main 中与 .wait() 无关。行为仍然是一样的 我在这里抛出另一个问题来评论:我的理解是如果主线程终止,它的所有子线程都会同时终止。这是真的吗? @Anish 你指的“行为”是什么? 这篇帖子似乎表明,如果主线程是 main() 方法所在的地方,则主线程(和进程)及其所有“子”线程将被终止,但如果它不是,所有的“子”线程都会继续执行。 ***.com/questions/4666628/…【参考方案2】:

这正是您不应该使用async void 的原因。在常规异步方法中,从方法主体抛出的异常被捕获并存储在返回的任务中。因为在async void 的情况下,调用者没有任务来观察异常导致进程停止。

所以,你应该返回一个任务,在Main的情况下你可以和Task.Wait同步阻塞:

private static void Main()

    CallAsync().Wait();


public static async Task CallAsync()

    var task = CallExceptionAsync();
    ThrowException("Outside");
    await task;

使用Task.Wait 阻塞不是真正的应用程序的合适解决方案,因为它可能导致涉及SynchronizationContext 的死锁。在这种情况下,您可以使用 Stephen Cleary 的 AsyncContext

【讨论】:

你能再深入一点 AsyncContext 吗? @Anish 它为没有任何控制台应用程序提供SynchronizationContext(与 UI 应用程序不同)。但这不是重点。关键是要避免async voidasync void 仅适用于事件处理程序。

以上是关于如何使用异步等待处理多个异常的主要内容,如果未能解决你的问题,请参考以下文章

如何快速使用异步函数?完成处理程序[重复]

如何等待来自 forEach 循环的多个异步调用?

C#中异步编程多个异常的处理方式

如何等待来自 for 循环的多个异步调用?

C#如何使用异步编程

基于任务的异步编程模式(TAP)的错误处理