BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Parallel and Asynchronous
.NET 4.0+

Parallel LINQ

The fifteenth and final part of the Parallel Programming in .NET tutorial leaves the examination of imperative programming using loops and tasks. It starts the description of declarative programming using Parallel Language-Integrated Query.

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