.NET(C#) TPL:Parallel循环和多个Task的异常处理

转载自MGEN

和for/foreach中发生异常的表现一样,Parallel循环中的任何异常都会使整个循环终止,注意由于整个循环是分块同时进行的,因此整个循环不会立即终止(如果有一个线程正在进行长时间工作的话,而且是发生在CancellationToken的ThrowIfCancellationRequested方法之后)。

代码:

try
{
    Parallel.For(0, 5, (i) =>
    {
        throw new Exception("异常。迭代数字:" + i);
    });
}
catch (AggregateException ae)
{
    foreach (var exp in ae.InnerExceptions)
        Console.WriteLine(exp.Message);
}

将会输出0-4的子集(也有可能是0-4全部输出,由于5个线程都快速运行完成)。

与Parallel.For和ForEach不一样,Parallel.Invoke总是会把所有任务都执行完,然后把所有的异常包装在AggregateException中。

来看这段代码:

try
{
    Parallel.Invoke(() => { throw new Exception("1"); },
                    () => { Thread.Sleep(1500); throw new Exception("2"); },
                    () => { Thread.Sleep(3000); throw new Exception("3"); });
}
catch (AggregateException ae)
{
    foreach (var ex in ae.InnerExceptions)
        Console.WriteLine(ex.Message);
}

结果会输出:

3
2
1

Task.WaitAll和Parallel.Invoke类似,任何一个(或多个)Task的异常不会影响任何其他Task的执行。

try
{
    var t1 = Task.Factory.StartNew(() => 
    { 
        Thread.Sleep(700);
        throw new Exception("1"); 
    });

    var t2 = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        throw new Exception("2");
    });

    Task.WaitAll(t1, t2);
}
catch (AggregateException ae)
{
    foreach (var exp in ae.InnerExceptions)
        Console.WriteLine(exp.Message);
}
 

同样会输出:

2
1
两个异常都会在AggregateException中的InnerExceptions属性中。

对于Task执行的异常(而不是Task.WaitAll),可以参考这篇文章:

.NET(C#) TPL:Task中未觉察异常和TaskScheduler.UnobservedTaskException事件

对于取消处理的异常可以参考:

.NET(C#) TPL:Task, Parallel, PLINQ中取消操作后的OperationCanceledException异常

Related Posts:
.NET(C#) TPL:Task, Parallel, PLINQ中取消操作后的OperationCanceledException异常
.NET(C#) TPL:Task中未觉察异常和TaskScheduler.UnobservedTaskException事件
.NET(C#):多个await和和异常处理
.NET(C#) TPL:TaskFactory.FromAsync与委托的异步调用


版权声明:本文为newjlwg原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。