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:
- There two versions of Test, one with explicit Try Catch and other without
- Both have similar inconsistent behavior to the extent that in Test1, even local try catch doesn't print the value
- There can be third version
Test3
which always work as exception is not explicitly thrown out of the parallel loop Dump
is a linqpad print call replace it byConsole.WriteLine
on the visual studio
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.
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.
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.
来源:https://stackoverflow.com/questions/52309855/parallel-foreach-loop-inconsistent-behavior-with-explicit-throw-statement