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