The Parallels

The Parallel static class gives us a few nice helper methods to carry out For, ForEach and Invoke methods in a parallel way. In reality we should say a potentially parallel way as there’s no guarantee they will be executed in separate tasks.

Parallel.ForEach

The ForEach method has several overloads, but basically this will loop through an IEnumerable passing each value into an Action. For example

int[] values = new[] { 3, 5, 1, 45, 12, 6, 49 };
Parallel.ForEach(values, Console.WriteLine);

The order in which the Console.WriteLine method is passed values is non-deterministic. In other words there’s no guarantee that 1 will be processed before 45 and so on. A key thing to remember is that all values will be processed before the Parallel.ForEach call returns control to the calling code. In other word a Wait stops the calling code to continue until all items in the enumerable object passed to the ForEach method have been processed.

This means if you run Parallel.ForEach from a UI thread then it will block even though each item placed into the ForEach list is potentially run in parallel. So you need to do something like

Task.Factory.StartNew(() => Parallel.ForEach(values, SomeAction));

Obviously if anything within the action needs to update the UI thread you’ll need to marshal it onto the UI thread.

Parallel.For

Along with the ForEach we also have the For loop. Which allows us to loop from a (inclusive) to b (exclusive) indices calling the supplied Action with the index. For example

int[] values = new[] { 3, 5, 1, 45, 12, 6, 49 };
Parallel.For(0, 2, i => Console.WriteLine(values[i]));

In this instance only “values” 3 and 5 will be passed to the action as we’re starting at (and including) index 0 and stopping before index 2 (as it’s exclusive). The same issues/traits exist for the For loop in that it is blocking etc.

Invoke

Finally we have Invoke which takes an array of Actions and calls them in a potentially parallel manner. Thus if we had several actions that we want to call potentially in parallel we can pass them to the Invoke method to be executed. For example

Parallel.Invoke(() => Console.WriteLine(3), 
                () => Console.WriteLine(4), 
                () => Console.WriteLine(5));

As per For and ForEach this method will potentially execute the actions in parallel but will block the calling thread.

Exceptions

If exceptions occur within the loops or invoke the Parallel library will throw an AggregationException which will contain one or more InnerExceptions.

ParallelLoopState

We can also pass a ParallelLoopState object into either the ForEach or For loops which allows us to Break or Stop a parallel loop as well as allowing us to find out whether a loop has exceptioned or is stopped etc.

ParallelOptions

Each of the For, ForEach and Invoke method have an overload which takes ParallelOptions. This enables us to set the maximum degree of parallelism, the task scheduler and the cancellation token.

The maximum degree of parallelism allows us to limit the possible number of threads uses in a Parallel method.

The cancellation token allows us a way to cancel a parallel task however this is a cooperative operations, in other words the algorithm writer must poll the cancellation token and take the action to cancel the algorithm etc. when the token is set to Cancel. Tasks are not interrupted or stopped in anyway, it’s down to the algorithm to detect and stop.

The task scheduler allows us to assign a custom scheduler to the parallel code.