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 For Loops for any Data Type

The standard parallel for loop is limited to working with integer values and only permits looping through an incrementing range, unlike its sequential equivalent. This article describes an alternative parallel for loop without these limitations.

Making the Method Generic

So far we've been working with decimal values. We can now convert the code to a generic method that can process a sequence of any data type in parallel. The updates are now trivial; we just need to replace references to decimal with a generic type parameter. The new code is shown below:

static void ParallelFor<T>(
    T start, Predicate<T> condition, Func<T, T> next, Action<T> function)
{
    var values = GenerateSequence(start, condition, next);
    Parallel.ForEach(values, function);
}

static IEnumerable<T> GenerateSequence<T>(T start, Predicate<T> condition, Func<T, T> next)
{
    for (T value = start; condition(value); value = next(value))
    {
        yield return value;
    }
}

To demonstrate, we can output all of the letters of the alphabet in parallel:

ParallelFor('a', c => c <= 'z', c => (char)(c + 1), c => { Console.Write(c); });

/* OUTPUT
     
acdbeiflmnopqrstuvwxyzhjgk

*/

Overloads

Parallel.For includes a number of overloaded versions. We can easily add similar overloads to our new method. In this article we will look at one but it's a minor matter to add some of the others if necessary. The one that we'll create is possibly the most important. It allows you to provide a ParallelLoopState parameter to the loop. This permits you to terminate the loop early if desired.

The Parallel.For loop provides the ParallelLoopState through a second parameter of the Action delegate. To do the same, add the following overloaded version of ParallelFor. No modifications to the sequence generating method are necessary.

static void ParallelFor<T>(
    T start, Predicate<T> condition, Func<T, T> next, Action<T, ParallelLoopState> function)
{
    var values = GenerateSequence(start, condition, next);
    Parallel.ForEach(values, function);
}

To demonstrate, try running the following code. This time the parallel loop state argument is used to break out of the loop immediately. In the sample output six iterations completed. These were already running or scheduled when the Break call was first processed.

ParallelFor('a', c => c <= 'z', c => (char)(c + 1), (c, pls) =>
{
    Console.Write(c);
    pls.Break();
});

/* OUTPUT
     
afdcbe

*/
5 October 2013