Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / .NET / .NET4

Parallel Programming Easier than ever using .NET Framework 4

4.86/5 (6 votes)
9 Sep 2010CPOL2 min read 17K  
Parallel programming is easier than ever using .NET Framework 4

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, foreach 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

C++
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 run your loop using an IEnumerable<TSource> parameter like Dictionary<>, List<>, Queue<>, Stack<> or anything in the System.Collections.Generic Namespace.

Usage Sample

C++
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

C++
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 let's try it in real life, below is an application that will zip a folder 100 times over and that folder consists of 2 files which are 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.

C++
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:\Test\FolderForCompression-" + 
     item + @".rar"" ""C:\Test\FolderForCompression""";
 myProcess.StartInfo.UseShellExecute = false;
 myProcess.StartInfo.RedirectStandardOutput = true;
 myProcess.Start();
}

Now, here are my results:

Image 1

The time spent for the processes to run is not that dramatic as it's only 47.38% improvement 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:

Image 2

This is the Parallel usage:

Image 3

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 background compared to one.

Image 4

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 these new processors, because if not, why is it there for.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)