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

时间:2014-06-26 17:54:13

标签: 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;
        }
    }
}

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

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

3 个答案:

答案 0 :(得分:8)

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

只需在Task之前保留对await的引用,以便稍后可以访问聚合例外,或者只是await WhenAll的结果而是使用手动延续。

答案 1 :(得分:4)

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

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

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

        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);
        }

答案 2 :(得分:0)

如果我运行以下示例,则所有任务都已完成但仍会抛出,我相信这是预期的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TaskWhenAllTest
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Task task = Test();

                Task.WaitAll(new Task[] { task });

                Console.WriteLine(task.Status);
            }
            catch (Exception)
            {
                //Console.WriteLine(ex.ToString());
                Console.WriteLine("Task errored.");
            }

            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        static async Task Test()
        {
            var task1 = Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(1000); throw new Exception("Test1 exception"); });
            var task2 = Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(500); Console.WriteLine("Task 2 complete."); });
            var task3 = Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(250); Console.WriteLine("Task 3 complete."); });

            await Task.WhenAll(new Task[] {task1, task2, task3 });
        }
    }
}