如何在 for 循环中并发运行异步函数并在 C 中捕获所有错误#

How to run async functions concurrently in a for loop AND catch all errors in C#

提问人:jumpingSloth 提问时间:8/26/2023 更新时间:8/26/2023 访问量:48

问:

我正在尝试对许多项目执行异步函数。此外,我想捕获此函数中可能抛出的所有错误。

运行以下代码时,我仍然收到“未处理的异常”错误,而不是 WriteLine 语句为每个项目打印的实际错误消息“某些错误”。

public async Task RunEachItem()
{
    var tasks = new List<Task>();

    foreach (var item in Items)
    {
        tasks.Add(SomeAsyncFunc(item.Index));
    }

    try
    {
        await Task.WhenAll(tasks);
    }
    catch(Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

public async Task SomeAsyncFunc(int index)
{
    // somehow process item using index parameter

    throw new Exception("some error");
}

我将非常感谢任何帮助,因为我没有找到如何使用谷歌或人工智能工具完成此操作。

C# 异步 错误处理

评论

4赞 Ben Voigt 8/26/2023
您正在正确地并发运行异步函数,并且您正确地捕获了错误。这段代码的唯一问题是认为这是有用的。e.Message
1赞 Ben Voigt 8/26/2023
您有两种可能的方法:检查并了解如何读取最有可能是 .或者读取哪个仍然是 AggregateException(但现在至少您知道是哪个调用导致了它)e.GetType()InnerExceptionsAggregateExceptiontasks[i].Exception
2赞 EyesShriveledToRaisins 8/26/2023
@jumpingSloth,那么您很可能没有运行与您在问题中发布的代码完全相同的代码。您正在执行的真实 SomeAsyncFunc 方法是什么样子的,它真的和问题中的一样吗?您是否正在以某种方式在问题中未显示的其他任何地方等待对 SomeAsyncFunc 的调用?
1赞 Servy 8/26/2023
@BenVoigt 该方法显示为 ,因此我们知道它永远不会抛出,只会返回一个错误的任务。async
1赞 Ben Voigt 8/26/2023
您的程序的任何其他部分是否调用?是否启动任何新线程或用于在自己的上下文之外执行工作?SomeAsyncFuncSomeAsyncFuncTask.Run

答:

0赞 Georgy Tarasov 8/26/2023 #1

您必须使用包含所有任务的可等待任务的属性。Exception.InnerExceptions

class Foo
{
    public async Task RunEachItem()
    {
        var tasks = new List<Task>();

        for (int i = 0; i < 10; i++)
        {
            tasks.Add(SomeAsyncFunc(i));
        }

        Task t = null!;
        try
        {
           t = Task.WhenAll(tasks);
           await t;
        }
        catch(Exception e)
        {
            var all = t.Exception.InnerExceptions;
            foreach (Exception exception in all)
            {
                Console.WriteLine(exception.Message);
            }
        }
    }

    public async Task SomeAsyncFunc(int index)
    {
        // somehow process item using index parameter

        throw new Exception($"some error {index}");
    }
}

此代码的输出将是

some error 0
some error 1
some error 2
...

评论

1赞 jumpingSloth 8/26/2023
多谢!这种方法效果很好,而且比我发布的方法更简单。
-1赞 jumpingSloth 8/26/2023 #2

在进一步搜索了 Google 的深度之后,我找到了这篇关于该主题的文章。 似乎围绕 the only 的 try-catch 语句捕获了第一个异常。因此,您需要用“缓冲区调用”包围异步函数,如下所示:await Task.WhenAll(tasks)


private async Task BufferCall(int index)
{
    try
    {
       await someAsyncFunc(index);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

// ...

tasks.Add(BufferCall(item.Index));

现在唯一的问题是,如果函数仍然以这种方式并发运行......

评论

0赞 Georgy Tarasov 8/26/2023
我认为如果作者想在过程结束时汇总所有引发的异常,这不是正确的方法