使用 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();
}
}
Details:
- 有两种版本的 Test,一种带有显式 Try Catch,另一种则没有
- 两者都有类似的不一致行为,在 Test1 中,即使是本地 try catch 也不会打印值
- 可以有第三个版本
Test3
它始终工作,因为异常没有明确地从并行循环中抛出
-
Dump
是一个 linqpad print 调用,将其替换为Console.WriteLine
在视觉工作室
有一个选项定义here,它收集所有异常ConcurrentQueue
并稍后将它们作为聚合异常抛出,但为什么当前代码不能按预期工作,我不太确定。在这种情况下,我们期望输出为:
1 - Odd value exception
3 - Odd value exception
5 - Odd value exception
但其中一些是随机跳过的,在简单的程序中也是如此,在复杂的程序中也会有更多的错过,这会做更多的工作
这完全是预期的行为。
See the docs,
未处理的异常导致循环立即终止
当您抛出异常时,不会安排新的任务。
所以行为会显得不可预测。您无权期望所有子任务都会执行。这不是 Parallel.For 循环的契约。
当您向源列表添加更多项目时,差异会更加明显。
输出将始终显示 ThreadPool.MinThreads 附近的许多异常。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)