Parallel.Foreach循环,行为与显式throw语句不一致 [英] Parallel.Foreach loop, inconsistent behavior with explicit throw statement

查看:101
本文介绍了Parallel.Foreach循环,行为与显式throw语句不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Linqpad创建了一个简单程序,其中我在 Parallel Foreach 循环中显式抛出异常,理想情况下,该异常将在调用方中被捕获为 Aggregate Exception ,但是当我显式抛出异常时,有时会随机跳过一些异常。我无法理解这种行为,任何人都可以解释:

Created a simple program using Linqpad, where I am throwing an exception explicitly in the Parallel Foreach loop, which ideally shall be caught in the caller as Aggregate Exception, but when I explicitly throw the exception, it sometimes skip out few exceptions on random basis. I am not able to understand the behavior, anyone who can explain:

void Main()
{
    try
    {
      var intList = new List<int> {1,2,3,4,5,6};

      Parallel.ForEach(intList, i => Test1(i));
    }
    catch (AggregateException aggregateException)
    {
        foreach (var ex in aggregateException.Flatten().InnerExceptions)
        {
            ex.Message.Dump();
        }
    }
}

public void Test1(int i)
{
    try
    {
        if (i % 2 != 0)
            throw new Exception($"{i} - Odd value exception");

    }
    catch(Exception ex)
    {
        ex.Message.Dump();
        throw;
    }
}

public void Test2(int i)
{
        if (i % 2 != 0)
            throw new Exception($"{i} - Odd value exception");
}

public void Test3(int i)
    {
        try
        {
            if (i % 2 != 0)
                throw new Exception($"{i} - Odd value exception");

        }
        catch(Exception ex)
        {
            ex.Message.Dump();
        }
    }



详细信息:



Details:


  1. 有两种版本的Test,一种具有明确的Try Catch,而另一种则没有

  2. 在Test1中,这两种行为都有相似的不一致之处,甚至本地try catch也不会显示值

  3. 可能存在第三个版本 Test3 ,该版本始终可以工作,因为未明确抛出异常并行循环

  4. 转储是linqpad打印调用,替换为 Console.WriteLine

  1. There two versions of Test, one with explicit Try Catch and other without
  2. Both have similar inconsistent behavior to the extent that in Test1, even local try catch doesn't print the value
  3. There can be third version Test3 which always work as exception is not explicitly thrown out of the parallel loop
  4. Dump is a linqpad print call replace it by Console.WriteLine on the visual studio

有一个选项定义此处,它收集中的所有异常ConcurrentQueue 并稍后将它们作为聚合异常抛出,但是为什么当前代码无法按预期运行,我不太确定。在这种情况下,我们期望输出为:

There's an option define here, which collects all exceptions in a ConcurrentQueue and throw them later as aggregated exception, but why the current code doesn't work as expected, I am not very sure. In this case we expect Output to be:

1 - Odd value exception
3 - Odd value exception
5 - Odd value exception

,但是其中一些被随机跳过,在一个简单程序中,

but some of them are randomly skipped, that too in a simple program, there are much more miss in a complex program, which do far more work

推荐答案

这是完全可以预期的行为。

This is entirely expected behaviour.

请参见文档


未处理的异常会导致循环立即终止

an unhandled exception causes the loop to terminate immediately

当您引发异常时,将不会安排新任务。

When you throw an exception, no new Tasks will be scheduled.

因此,行为似乎不可预测。您无权期望所有子任务都将执行。那不是Parallel.For循环的约定。

So the behaviour will appear unpredictable. You have no right to expect that all subtasks will execute. That is not the contract of a Parallel.For loop.

当您向源列表中添加更多项时,差异将更加明显。
输出将始终在ThreadPool.MinThreads附近显示许多异常。

The difference will be much clearer when you add more items to the source list. The output will always show a number of exceptions in the neighbourhood of ThreadPool.MinThreads.

这篇关于Parallel.Foreach循环,行为与显式throw语句不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆