简体   繁体   English

Parallel.Foreach循环,行为与显式throw语句不一致

[英]Parallel.Foreach loop, inconsistent behavior with explicit throw statement

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. 使用Linqpad创建了一个简单程序,其中我在Parallel Foreach循环中显式抛出一个异常,理想情况下,该Aggregate Exception应作为Aggregate Exception被捕获在调用方中,但是当我显式抛出该异常时,它有时会随机地跳过一些异常。 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. There two versions of Test, one with explicit Try Catch and other without 有两个版本的Test,一个带有显式的Try Catch,另一个没有
  2. Both have similar inconsistent behavior to the extent that in Test1, even local try catch doesn't print the value 在Test1中,两者都具有相似的不一致行为,即使本地try catch也不会输出值
  3. There can be third version Test3 which always work as exception is not explicitly thrown out of the parallel loop 可以有第三个版本Test3 ,它总是可以正常工作,因为没有明确地将异常排除在并行循环之外
  4. Dump is a linqpad print call replace it by Console.WriteLine on the visual studio Dump是linqpad打印调用,在Visual Studio中由Console.WriteLine代替

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. 有一个选项定义在这里 ,收集在所有异常ConcurrentQueue它们扔后来由于聚集的例外,但为什么如预期当前代码不工作,我不是很肯定。 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. 这完全是预期的行为。

See the docs , 参见文档

an unhandled exception causes the loop to terminate immediately 未处理的异常导致循环立即终止

When you throw an exception, no new Tasks will be scheduled. 引发异常时,不会安排任何新任务。

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. 那不是Parallel.For循环的约定。

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. 输出将始终在ThreadPool.MinThreads附近显示许多异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM