繁体   English   中英

Task.WhenAll 是否等待所有任务以防出现异常

[英]Does Task.WhenAll wait for all the tasks in case of exceptions

我有两个任务。 我用 Task.WhenAll 运行它们。 如果其中之一抛出异常会怎样? 另一个会完成吗?

只需运行这段代码来测试它:

private static async Task TestTaskWhenAll()
{
    try
    {
        await Task.WhenAll(
            ShortOperationAsync(),
            LongOperationAsync()
        );
    }
    catch (Exception exception)
    {
        Console.WriteLine(exception.Message); // Short operation exception
        Debugger.Break();
    }
}

private static async Task ShortOperationAsync()
{
    await Task.Delay(1000);
    throw new InvalidTimeZoneException("Short operation exception");

}

private static async Task LongOperationAsync()
{
    await Task.Delay(5000);
    throw new ArgumentException("Long operation exception");
}

调试器将在 5 秒后停止。 两个异常都被抛出,但Debugger.Break()只被命中一次。 而且, exception值不是AggregateException ,而是InvalidTimeZoneException 这是因为新的async/await将展开到实际的异常中。 您可以在此处阅读更多内容。 如果要读取其他Exceptions (不仅是第一个异常),则必须从WhenAll方法调用返回的Task中读取它们。

另一个会完成吗?

它不会因为另一个失败而停止

但它会完成吗?

Task.When将等待所有完成,无论有没有失败。 我刚刚用这个进行了测试以验证 - 需要 5 秒才能完成:

Task allTasks = Task.WhenAll(getClientToken, getVault, Task.Delay(5000)); 

如果您想对任务进行分组,您可以创建一个“新任务”,然后等待。

Task allTasks = Task.WhenAll(getClientToken, getVault, Task.Delay(5000)); 

try 
{
    await allTasks;

} catch (Exception ex) 
{

   // ex is the 'unwrapped' actual exception
   // I'm not actually sure if it's the first task to fail, or the first in the list that failed

   // Handle all if needed
   Exceptions[] allExceptions = allTasks.Exceptions;

   // OR
   // just get the result from the task / exception
   if (getVault.Status == TaskStatus.Faulted) 
   {
       ...
   }
}

有同样的问题,自己测试过。 简而言之:

  • 它总是等待所有任务完成。

  • 如果在所有任务完成后有任何异常,则抛出第一个异常(如果不捕获则崩溃)。

  • 对于所有异常,保留Task.WhenAll返回的Task实例并使用Exception.InnerExceptions属性。

这是我的测试:

    static async Task Main(string[] args)
    {
        var tasks = new[] { Foo1(), Foo2(), Foo3() };

        Task t = null;
        try
        {
            t = Task.WhenAll(tasks);
            await t;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
        }

        Console.WriteLine("All have run.");

        if (t.Exception != null) 
        {
            foreach (var ex in t.Exception.InnerExceptions)
            {
                Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
            }
        }

    }

    static async Task Foo1()
    {
        await Task.Delay(50);
        throw new ArgumentException("zzz");
    }

    static async Task Foo2()
    {
        await Task.Delay(1000);
        Console.WriteLine("Foo 2");
        throw new FieldAccessException("xxx");
    }

    static async Task Foo3()
    {
        for (int i = 0; i < 10; i++)
        {
            await Task.Delay(200);
            Console.WriteLine("Foo 3");
        }
    }

输出:

Foo 3
Foo 3
Foo 3
Foo 3
Foo 2
Foo 3
Foo 3
Foo 3
Foo 3
Foo 3
Foo 3
ArgumentException: zzz
All have run.
ArgumentException: zzz
FieldAccessException: xxx

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM