Parallel Programming Easier than ever using .NET Framework 4

By | September 9, 2010

The .NET Framework 4 Provides support for parallel loops and regions easily if you compare to the older versions of .Net such as using System.Threading now with the introduction of the Parallel class it now provides library-based data parallel operations such as for loops, for each loops, and invoke actions.

The new namespace is the System.Threading.Tasks. The methods are:


Parallel.For()

Executes a for loop where the iterations run in parallel.  This method is useful if you want to invoke the same method where you run your loop using a parameter like a counter.

Usage Sample:

static void Main(string[] args)
{
    int LoopCounter = 50;

    Parallel.For(0, LoopCounter, i =>
    {
        DoSomething(i);
        Console.ReadLine();
    }
    );
}
public static void DoSomething(int item) { Console.WriteLine("DoSomething " + item.ToString() + " : " + DateTime.Now); }

Parallel.ForEach()

Executes a foreach operation on an IEnumerable<TSource> where the iterations run in parallel.  This method is useful if you want to invoke the same method where you rin your loop using a IEnumerable<TSource> parameter like Dictionary<>, List<>, Queue<>, Stack<> or anything in the System.Collections.Generic Namespace.

Usage Sample:

static void Main(string[] args)
{
    List<int> myList = new List<int>();
    for (int i = 0; i < 500; i++) { myList.Add(i); }

    Parallel.ForEach(myList, item =>
    {
        DoSomething(item);
        Console.ReadLine();
    }
    );
}

public static void DoSomething(int item) { Console.WriteLine("DoSomething " + item.ToString() + " : " + DateTime.Now); }

Parallel.Invoke()

Executes each of the provided actions in parallel.  This method is useful if you want to invoke different methods in one go.

Usage Sample:

static void Main(string[] args)
{
    Parallel.Invoke(DoSomething1, DoSomething2, DoSomething3);
    Console.ReadLine();
}
public static void DoSomething1() { Console.WriteLine("DoSomething 1 : " + DateTime.Now); }
public static void DoSomething2() { Console.WriteLine("DoSomething 2 : " + DateTime.Now); }
public static void DoSomething3() { Console.WriteLine("DoSomething 3 : " + DateTime.Now); }

Now lets try it in real life, below is an application that will zip a folder 100 times over and that folder consists of 2 file which is 9 MB data the first test will be using the normal loop in a linear fashion and the second test will be using parallel execution.

static void Main(string[] args)
{
 switch (args[0].ToString())
 {
 case "1":
 DateTime dDateStart = DateTime.Now;
 Console.WriteLine("Non Threaded - Start : " + dDateStart);
 DoLinear();
 DateTime dDateEnd = DateTime.Now;
 Console.WriteLine("Non Threaded - End : " + dDateEnd);
 System.TimeSpan TimeRun = dDateEnd - dDateStart;
 Console.WriteLine("Time Spent in ms : " + TimeRun.Milliseconds);
 break;
 case "2":
 DateTime dDateStart2 = DateTime.Now;
 Console.WriteLine("Non Threaded - Start : " + dDateStart2);
 DoParallel();
 DateTime dDateEnd2 = DateTime.Now;
 Console.WriteLine("Non Threaded - End : " + dDateEnd2);
 System.TimeSpan TimeRun2 = dDateEnd2 - dDateStart2;
 Console.WriteLine("Time Spent in ms : " + TimeRun2.Milliseconds);
 break;
 default:
 break;
 }
}

private static void DoLinear()
{
 int LoopCounter = 100;

 for (int x = 0; x < LoopCounter; x++)
 {
 PerformZip(x);
 }

}

private static void DoParallel()
{
 int LoopCounter = 100;

 Parallel.For(0, LoopCounter, i =>
 {
 PerformZip(i);
 }
 );
}
private static void PerformZip(int item)
{
 Process myProcess = new Process();
 myProcess.StartInfo.FileName = "rar.exe";
 myProcess.StartInfo.Arguments = @"a -m1 -r ""C:TestFolderForCompression-" + item + @".rar"" ""C:TestFolderForCompression""";
 myProcess.StartInfo.UseShellExecute = false;
 myProcess.StartInfo.RedirectStandardOutput = true;
 myProcess.Start();
}

Now here are my results


The time spend for the processes to run is not that dramatic as its only 47.38% imporvement but this is just a sample and there is an improvement, but try to imagine if you are doing a distributed application where you have workstations that do the work where the work thread is invoked from a central server definitely it will have a dramatic impact (this is where I had applied this in a real project) as the commands coming from the central server will not be linear anymore.

To dig deeper I had checked the processor usage during the test

This is the Non-Parallel usage

This is the Parallel usage

Notice we had used at max 100% of all of the 8 cores in the machine compared to 12% also  you will see that there are now multiple rar programs that are running on the backround compared to one

I think with the new age processors with multi core and multi threaded technology we need to use more threaded programming to make use of this new processors because if not why is it there for.


Leave a Reply