即使抛出异常,也执行所有任务

jga*_*fin 3 c# task-parallel-library

我有以下方法:

public async Task PublishAsync<TApplicationEvent>(TApplicationEvent e)
    where TApplicationEvent : ApplicationEvent
{
    using (var scope = _container.CreateScope())
    {
        var implementations = scope.ResolveAll<IApplicationEventSubscriber<TApplicationEvent>>();
        var tasks = implementations.Select(x => x.HandleAsync(e));
        try
        {
            await Task.WhenAll(tasks);
            EventPublished(this, new EventPublishedEventArgs(scope, e, true));
        }
        catch
        {
            EventPublished(this, new EventPublishedEventArgs(scope, e, false));
            throw;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为所有任务都将在抛出异常之前执行,但似乎该方法在第一个任务抛出异常时中止.

我可以配置WhenAll执行所有任务并在返回之前生成包含所有失败的AggregateException吗?

Ser*_*rvy 8

这正是WhenAll 做了什么.但是,当您await抛出一个在其中有多个异常的聚合异常的任务时,它将仅重新抛出聚合异常中的第一个异常,而不是重新抛出聚合异常本身.(这是因为抛出异常的绝大多数任务在聚合中永远不会有多个表达式,因此解除异常几乎总是所需的行为.)

只需保留对它Task之前的引用,await以便以后可以访问聚合异常,或者只是不await使用结果WhenAll而是使用手动延续.

  • @jgauffin在所有给定任务完成之前,你在'WhenAll`中找到导致它完成的错误的概率非常小.你很可能没有测试你认为你正在测试的东西,也就是没有把你认为你传递的东西传递给'WhenAll`或者没有正确地观察效果.听起来您的测试框架只是在这里妨碍您.只需显式创建两个你想要的任务,至少有一个错误,将它们传递给`WhenAll`,并看到它们在任务完成后全部完成. (2认同)

Sur*_*lik 5

Task.WhenAll() -> 创建一个任务,该任务将在所有提供的任务完成后完成。

无论单个任务中发生什么,它将完成所有任务的执行。

给定任务集合中的任务之一出现异常不会停止其他任务的执行。

        var tasks = new List<Task>();

        Task t1 = Task.Run(() =>
        {
            throw new Exception("test1");
        });
        tasks.Add(t1);

        Task t2 = Task.Run(() =>
        {
            throw new Exception("test2");
        });
        tasks.Add(t2);

        Task t3 = Task.Run(() =>
        {
            Console.WriteLine("Pseudo Work");
        });
        tasks.Add(t3);

        try
        {
            await Task.WhenAll(tasks);
        }
        catch (Exception ex)
        {
            // Only t1 & t2 will qualify and t3 will be successful (Pseudo Work will be printed on console) 
            var exceptions = tasks.Where(t => t.Exception != null).Select(t => t.Exception);
        }
Run Code Online (Sandbox Code Playgroud)