Using AsParallel with Query Expression Syntax
Let's look at parallelising a query defined using query expression syntax. First, we need a suitable query. We'll again generate the squares of source sequence. To do so, replace the previous query line with the following:
var squares =
from x in sequence
select x * x;
// 1 4 9 16 25 36 49 64 81 100
Again, to run the query in parallel we simply apply the AsParallel method to the source data, as shown below:
var squares =
from x in sequence.AsParallel()
select x * x;
// 1 36 4 49 9 64 16 81 25 100
As before, we can preserve the order of the results using the AsOrdered method:
var squares =
from x in sequence.AsParallel().AsOrdered()
select x * x;
// 1 4 9 16 25 36 49 64 81 100
Handling Exceptions with PLINQ
When you execute a sequential query using LINQ, any one of the data items processed may lead to an exception. When an exception is thrown, the query stops executing immediately. With PLINQ, it is possible for the processing of multiple items to be executing concurrently. If one of these throws an exception, all of the other threads will stop but only after any scheduled operations have completed. This may mean that there is a delay between the exceptional event and the PLINQ query halting if the query operations are slow. It also means that any of the other parallel operations may also throw an exception.
To deal with the possibility of a query causing multiple exceptions, all exceptions from a PLINQ query are combined in a single AggregateException, which is thrown when all of the threads of execution stop. As when using parallel loops and tasks, you can capture this and examine its InnerExceptions property to find all of the thrown exceptions.
To demonstrate, try executing the following sample code several times. This code performs a number of division operations. Two of the values in the sequence are zero and will cause a DivideByZeroException. When you run the code you will see that sometimes one exception is thrown and sometimes two, depending upon whether a second zero is encountered before the first exception halts the entire query.
int[] sequence = new int[] { 1, 2, 3, 4, 0, 6, 12, 24, 48, 0 };
var results =
from x in sequence.AsParallel()
select 96 / x;
try
{
foreach (var result in results)
{
Console.Write(result + " ");
}
}
catch (AggregateException ex)
{
foreach (var exception in ex.InnerExceptions)
{
Console.WriteLine(exception.Message);
}
}
/* OUTPUT
Attempted to divide by zero.
Attempted to divide by zero.
*/
29 November 2011