The Parallel.For loop construct provided by Parallel Extensions is focused on providing a parallel alternative to the common sequential pattern of a for loop that iterates over a range of numbers. However, the for loop construct in a language like C# is not limited just to numbers and iterating over ranges. It supports arbitrary initialization, condition, and update expressions, for example:
for(var i = init(); cond(i); i = upd(i)) { Use(i); }
There isn’t any built-in Parallel construct that supports this pattern. However, one of our goals with Parallel Extensions is to provide the foundational support to add these types of constructs easily on top of what we do provide. This is a good example of that. Consider the following implementation:
public static void ParallelFor<T>(
Func<T> init, Func<T,bool> cond, Func<T,T> upd, Action<T> body)
{
Parallel.ForEach(Iterate(init, cond, upd), body);
}private static IEnumerable<T> Iterate<T>(
Func<T> init, Func<T,bool> cond, Func<T,T> upd)
{
for(var i=init(); cond(i); i = upd(i)) yield return i;
}
As you can see, it was straightforward to create a parallel For method that accepted arbitrary initialization, condition, and update expressions. This was done by creating an iterator in C# for looping as was done in the original sequential example, and then passing the result of an invocation of that iterator to a call to Parallel.ForEach. We can now use this construct. For example, let’s say I have a linked list of nodes, and I want to execute some substantial amount of code for every node in the list. Sequentially, that might look like:
for(Node n = list; n != null; n = n.Next)
{
Process(n);
}
With our new ParallelFor method, we can do the same thing in parallel:
ParallelFor(() => list, n => n != null, n => n.Next, n =>
{
Process(n);
});
Simplicity. Of course, there are many other ways the ParallelFor method could be implemented; building on top of Parallel.ForEach is just one of them.
0 comments