Jennifer Marsman

Windows Development

Parallel.For in .NET 4.0

Parallel.For in .NET 4.0

  • Comments 1

In version 4.0 of the .NET Framework, there is a lot of support for parallel programming.  One cool class to know is System.Threading.Parallel, which contains a number of static methods to parallelize loops and regions. 

Consider this code which uses a for loop: 

static void ComputePerfectSquares1()
{
    Int64[] perfectSquares = new Int64[arraySize];

    for (int i = 0; i < arraySize; i++)
    {
        perfectSquares[i] = i * i;
        Thread.SpinWait(waitTime);  // Pretending this is more computationally difficult
    }
}

This is a simple example that calculates perfect squares.  Because that is a relatively cheap operation, I've also added a Thread.SpinWait to simulate a more computationally expensive action. 

Now, I'll write a second method which uses the new Parallel.For.  This is one of the static methods on the Parallel class. 

static void ComputePerfectSquares2()
{
    Int64[] perfectSquares = new Int64[arraySize];

    Parallel.For(0, arraySize, i =>
    {
        perfectSquares[i] = i * i;
        Thread.SpinWait(waitTime);  // Pretending this is more computationally difficult
    });
}

The arguments of the parallel for are very similar to the information we provided to the original for.  The first argument is the start index (inclusive) and the second argument is the end index (exclusive).  I passed in 0 and arraySize, respectively.  Then the third argument is the body to be invoked on each iteration; I'm using a lambda expression to do this.  There are also some optional parameters with other method overloads. 

Next, I wrote some code to test the relative performance of these methods:

static void Main(string[] args)
{
    DateTime startTime;
    TimeSpan duration;

    // Run using original for
    startTime = DateTime.Now;
    ComputePerfectSquares1();
    duration = DateTime.Now - startTime;
    Console.WriteLine("Original for: " + duration.TotalMilliseconds + " ms");

    // Run using parallel for
    startTime = DateTime.Now;
    ComputePerfectSquares2();
    duration = DateTime.Now - startTime;
    Console.WriteLine("Parallel for: " + duration.TotalMilliseconds + " ms");

    // Pause so output can be read.  
    Console.Read();
}

If I run this code (with arraySize = 1000 and waitTime = 5000000), here are my results:

ParallelForOutput

Running in parallel has cut my processing time down by roughly half (which makes sense since my machine has two cores), from 25.5 seconds to 13.5 seconds.  Fabulous! 

However, note that if I remove the "Thread.SpinWait" and run again, the original for loop performs better than the parallel for loop: 

ParallelForOutputWithoutSpinWait

This is because there is some overhead to using the parallel version.  The lesson here: don't parallelize all of your work blindly, but measure performance, find out where the computationally-expensive bottlenecks are and if they can be broken down into smaller chunks that can be run in parallel, and then use this functionality there.  The Parallel class is a wonderful resource, giving you an easy way to run a for loop (and other programming constructs) in parallel. 

For reference, I've attached the entirety of my program.  Note that I did do some refactoring from the code above (which contains a lot of duplication), but I thought it was easier to understand if I inlined in the examples above. 

Attachment: ParallelConsoleApp.zip
  • Loading...
Leave a Comment
  • Please add 2 and 4 and type the answer here:
  • Post