【问题标题】:Parallel.Foreach loop, inconsistent behavior with explicit throw statementParallel.Foreach 循环,与显式 throw 语句不一致的行为
【发布时间】:2018-09-13 08:42:39
【问题描述】:

使用 Linqpad 创建了一个简单的程序,我在 Parallel Foreach 循环中显式抛出异常,理想情况下应在调用者中捕获为 Aggregate Exception,但是当我显式抛出异常时,它有时会跳过一些随机例外。我无法理解这种行为,谁能解释一下:

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

详情:

  1. Test 有两个版本,一个带有显式 Try Catch,另一个没有
  2. 两者都有类似的不一致行为,以至于在 Test1 中,即使本地 try catch 也不打印值
  3. 可以有第三个版本Test3,因为异常没有明确地从并行循环中抛出
  4. Dump 是一个 linqpad 打印调用,在 Visual Studio 上将其替换为 Console.WriteLine

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

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

但其中一些是随机跳过的,在一个简单的程序中也是如此,在一个复杂的程序中会有更多的失误,这会做更多的工作

【问题讨论】:

  • @MickyD 不,我没有,这纯粹是为了学习,否则 MSDN 链接中的模式很好
  • 优秀。谢谢
  • Parallel.For/Foreach 用于数据并行。它创建与核心数量大致相同的工作任务,对数据进行分区并将每个分区提供给一个任务。如果任何这些任务抛出,则继续进行计算是没有意义的。

标签: c# .net task-parallel-library parallel.foreach aggregateexception


【解决方案1】:

这完全是预期的行为。

docs

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

当您抛出异常时,不会安排新的任务。

因此行为将显得不可预测。您无权期望所有子任务都会执行。这不是 Parallel.For 循环的合同。

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

【讨论】:

猜你喜欢
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
  • 2017-05-30
  • 2020-12-24
  • 1970-01-01
  • 2011-05-11
  • 2011-07-10
  • 2014-09-21
相关资源
最近更新 更多