I am using PLINQ with code below:
static void Main(string[] args)
{
var lt = new List<int>() {1,2,3,4,5};
try
{
var nlt = lt.AsParallel().Select(Test).ToList();
}
catch (AggregateException e)
{
foreach (var ex in e.InnerExceptions)
{
Console.WriteLine(ex.Message);
}
}
}
private static bool Test(int n)
{
if (n == 1)
{
Thread.Sleep(1000);
}
if (n == 3)
{
Thread.Sleep(3000);
}
if (n == 5)
{
Thread.Sleep(5000);
}
if (n == 2 || n == 4)
{
throw new Exception("New exception");
}
Console.WriteLine("element : {0}", n);
return true;
}
The result is an aggregateException always thrown after 5s(until the last thread has finished). It seems that if some threads throw an exception, rest of the thread will still keep running. Upon completion of the last thread, the framework aggregates all exceptions and wraps them in an aggregateException.
Is it the framework behaviour that if 3 of out 10 threads throw exceptions, it will wait for the rest 7 threads to finish and throw aggreagteException at the end.
However, when I came across this document: https://msdn.microsoft.com/en-us/library/dd460712(v=vs.110).aspx
the query cannot continue after the exception is thrown. By the time your application code catches the exception, PLINQ has already stopped the query on all threads.
I wonder why my code doesn't behave in that way? If query cannot continue after exception is thrown, element 1, 3, 5 will not never be printed as the exception will have been throw already.
From the link that you've provided:
When exceptions are allowed to bubble up back to the joining thread, then it is possible that a query may continue to process some items after the exception is raised.
This section of albahari's article better explains what is happening:
Both PLINQ and the Parallel class end the query or loop execution upon encountering the first exception — by not processing any further elements or loop bodies. More exceptions might be thrown, however, before the current cycle is complete. The first exception in AggregateException is visible in the InnerException property.
When an exception is thrown, no more values from the collection will be processed. However, by the time the exceptions are thrown, the method Test(int)
has already been called for all 5 ints. In this case, PLINQ will wait for these method calls (the current cycle) and, upon completion of them all, throw the AggregateException
.