Async/Await 异常处理混乱

问题描述 投票:0回答:1

我试图理解 .net8 中的 async/await,特别是异常处理,但我遇到了一些困惑,特别是关于文档,因为它指定了一些方法,但没有提供足够的示例让我理解什么是正在发生。

我使用以下简单代码只是为了观看某些内容的工作:

private static async Task Main(string[] args) {
 var sleeps = new int[] { 1, 2, 3, 0 };
 var tasks = new List<Task<int>>();
 foreach (var t in sleeps)
 {
     Console.WriteLine("Submitting task: {0}", t);
     tasks.Add(sleep(t));
 }
 Console.WriteLine("All tasks submitted, waiting for all to complete");
 try
 {
     Task.WaitAll(tasks.ToArray());
 } catch (DivideByZeroException e)
 {
     Console.WriteLine("One of the tasks failed: {0}", e);
 }
 Console.WriteLine("All tasks completed, collecting results");
 foreach (var t in tasks)
 {
     Console.WriteLine("Task returned: {0}", t.Result);
 }
}

 private static async Task<int> sleep(int s)
 {
     Console.WriteLine("Sleeping for: [ {0} ]", s);
     if (s == 0)
     {
         // this is just to throw something to be caught
         throw new DivideByZeroException("0 can't be delayed");
     }
     await Task.Delay(s * 1000);
     Console.WriteLine("\tSlept for: [ {0} ]", s);
     return s;
 }

我正在关注这里的文档:

这里:

根据文档,我应该在进入代码的异步部分之前尝试在异步函数中抛出异常。您可以在我的示例中看到,我在等待 Task.Delay 之前抛出 ZeroDivision 异常。

当我在 Visual Studio 中运行此代码时,我希望能够命中 DivideByZeroException catch 块,但我得到了一个 SystemAggregateException,我理解这是 .net 如何收集所有异步异常,但是文档明确指出:

When code awaits a faulted task, the first exception in the AggregateException.InnerExceptions collection is rethrown
。但是,我根本没有抛出 DivideByZero 异常,而是依次抛出 2 个 SystemAggregate 异常,每个异常的第一个 innerException 是 DivideByZero 异常。

这里发生了什么事。

我还在这里编写了早餐示例:使用 async 和 wait 进行异步编程,并添加了烤面包机着火,这更加令人困惑,因为当我显式抛出异常时,我不会在任何地方抛出异常。我必须检查

Task.Exception
看看它是否被抛出。

那么谁能解释一下这里发生了什么?

如果我想提交 5 个异步任务,等待所有任务完成,然后迭代它们以检查它们的

Result
Exception
属性,我会使用什么方法?我不明白何时尝试/捕获、何时检查 Task.Exception 以及为什么我在示例代码中遇到 SystemAggregate 异常。

c# .net asynchronous async-await task-parallel-library
1个回答
0
投票

异步

AggregateException
方法不会抛出
sleep
。它是由同步
Task.WaitAll
方法抛出的:

例外情况

聚合异常 至少有一个

Task
实例被取消。如果任务被取消,
AggregateException
会在其
OperationCanceledException
集合中包含
InnerExceptions

解决您问题的最佳解决方案很可能将

Task.WaitAll
替换为异步
Task.WhenAll

try
{
    await Task.WhenAll(tasks.ToArray());
}
catch (DivideByZeroException e)
{
    Console.WriteLine("One of the tasks failed: {0}", e);
}

这也将消除您可能看到的关于不包含任何 async Task Main

await
方法的
 警告

如果您想同步等待任务,并且您喜欢

await
只传播一个异常的行为,您可以像这样使用
.GetAwaiter().GetResult()

try
{
   Task.WhenAll(tasks.ToArray()).GetAwaiter().GetResult();
}
catch (DivideByZeroException e)
{
    Console.WriteLine("One of the tasks failed: {0}", e);
}

这将阻塞当前线程,直到所有任务完成,并将根据 .NET 运行时版本,按位置或按时间顺序传播失败任务之一的异常。您可以查看此 GitHub 问题,了解有关传播哪个任务的异常的详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.