【发布时间】: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();
}
}
详情:
- Test 有两个版本,一个带有显式 Try Catch,另一个没有
- 两者都有类似的不一致行为,以至于在 Test1 中,即使本地 try catch 也不打印值
- 可以有第三个版本
Test3,因为异常没有明确地从并行循环中抛出 -
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