PLINQ异常

3

我正在使用以下代码的 PLINQ :

static void Main(string[] args)
    {
        var lt = new List<int>() {1,2,3,4,5};
        try
        {
            var nlt = lt.AsParallel().Select(Test).ToList();
        }
        catch (AggregateException e)
        {
            foreach (var ex in e.InnerExceptions)
            {
                Console.WriteLine(ex.Message);
            }
        }

    }

    private static bool Test(int n)
    {
        if (n == 1)
        {
            Thread.Sleep(1000);
        }
        if (n == 3)
        {
            Thread.Sleep(3000);
        }
        if (n == 5)
        {
            Thread.Sleep(5000);
        }
        if (n == 2 || n == 4)
        {
            throw new Exception("New exception");
        }
        Console.WriteLine("element : {0}", n);
        return true;
    }

结果是一个聚合异常,总是在5秒后抛出(直到最后一个线程完成)。似乎如果一些线程抛出异常,其余的线程仍然会继续运行。在最后一个线程完成后,框架会汇总所有的异常并将它们包装在一个聚合异常中。
如果10个线程中有3个线程抛出异常,那么框架会等待剩下的7个线程完成,并在最后抛出聚合异常,这是否是框架的行为。
然而,当我看到这份文档时: https://msdn.microsoft.com/en-us/library/dd460712(v=vs.110).aspx 引用如下:
“一旦抛出异常,查询就无法继续进行。当应用程序代码捕获异常时,PLINQ已经停止了所有线程上的查询。”
我想知道为什么我的代码没有表现出这种方式?如果查询在抛出异常后不能继续,那么元素1、3、5就不会被打印,因为异常已经被抛出了。
1个回答

7

从您提供的链接中:

当允许异常向上冒泡到加入线程时,查询可能在引发异常后继续处理一些项目。

此部分 albahari 文章更好地解释了正在发生的情况:

PLINQ 和 Parallel 类都会在遇到第一个异常时结束查询或循环执行 —— 不再处理任何其他元素或循环体。但在当前周期完成之前,可能会抛出更多的异常。AggregateException 中的第一个异常可在 InnerException 属性中看到。

当抛出异常时,集合中不会再处理更多值。但是,在抛出异常时,方法 Test(int) 已经被调用了所有 5 个 int。在这种情况下,PLINQ 将等待这些方法调用(当前周期)并在全部完成后抛出 AggregateException


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接