为什么在异步Parallel.ForEach中的异常会导致应用程序崩溃?

3
为什么下面的代码在控制台应用程序中运行时会崩溃,而不是抛出AggregateException并被外部try/catch捕获?
为了简洁起见,我已经简化了使用await的用例,但在相关代码中,我确实尝试执行一个重要的可等待任务(awaitable Task)。
var list = new List<string>() {"Error"};

        try
        {
            Parallel.ForEach(list, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 8
            }, async listEntry =>
            {
                await Task.Delay(5000);
                throw new Exception("Exception");
            });
        }
        catch (Exception ex)
        {
            //never hits, the application crashes
        }

        Console.ReadLine();

我注意到以下内容不会导致应用程序失败,确实捕获了异常,但我不理解两种情况之间根本的不同之处:

请注意,以下内容不会导致应用程序失败,并且确实捕获了异常,但我不明白两个上下文在根本上有什么不同:

var list = new List<string>() {"Error"};

        try
        {
            Parallel.ForEach(list, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 8
            }, listEntry =>
            {

                throw new Exception("Exception");
            });
        }
        catch (Exception ex)
        {
            //exception is caught, application continues
        }

        Console.ReadLine();

3
不要将Parallel.ForEachasync/await混合使用 https://dev59.com/aWgu5IYBdhLWcg3wHjl7 - user585968
@GrantH。你没有等待异步方法/lambda的result。如果你设置了很长时间的延迟并调试代码,你应该能够轻松地观察到它-循环将在抛出任何异常之前结束。一些来自https://dev59.com/4WEh5IYBdhLWcg3wfjiq的链接可以帮助理解问题(如果你找到了正确的解释方法,请随时编写自我答案)。 - Alexei Levenkov
这是关于编程的内容,以下是翻译文本:(顺便说一句,这个解决方案可以解决你的问题,但不是重复的,因为它没有解释你看到的东西 - Task.WhenAll - https://dev59.com/Cmct5IYBdhLWcg3wHJ3F) - Alexei Levenkov
@AlexeiLevenkov,也许我太蠢了,如果是这样,我道歉。但是当我设置5000ms的延迟时,代码按预期等待5秒钟,然后抛出异常并崩溃。我正在等待Task.Delay(5000)。循环不会提前结束。 - Grant H.
1
@MickyD,谢谢你提供的链接,非常有帮助,看来我的整个方法都有些偏差。 - Grant H.
显示剩余9条评论
1个回答

9

如在评论中已经提到的那样,您不应该将 asyncParallel.ForEach 混合使用,它们不兼容。

你观察到的是这种混合使用的后果之一:lambda 表达式被编译成一个 async void 方法,当一个 async void 方法抛出异常时,该异常会在其 SynchronizationContext 上重新抛出,这通常会导致应用程序崩溃。


谢谢您的解释,非常有帮助。 - Grant H.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接