Use all the CPU Power and take advantage of parallel programming with just two lines of code!
Yup, That’s correct, with two lines of code.
Note: If you want to download the source code for the code that is used here, please sign up here and get the source.
In general, Parallel programming is very difficult, you have to know about Threads, Multi-Threading, Cancellation Tokens, Deadlocks and all kinds of weird things that might happen if you are just starting in this area.
Recently in our team meeting, I talked about a very simple but super powerful class in .NET that only has 3 methods.
you might have already used it, but for the rest of us, that just found about it this very cool.
In System.Threading.Tasks namespace, there is a class called “Parallel“. It has only 3 methods, with a bunch of overloads for those 3 methods.
Parallel.For Parallel.ForEach Parallel.Invoke
The most basic usage of the first two is very easy to implement. In fact, if you already have a CPU intensive loop somewhere in your code, you just replace it with Parallel.For, and make it 2 to 6 times (or more) faster. (results may vary, depending on the type of loop and CPU Threads)
Let’s look at an example:
To demonstrate how this works, let’s create a simple function that his main purpose is to make the computer brain busy 🙂
It is going to loop through numbers with small increments.
Now that we have a function that keeps the computer busy, let’s create a function to use it:
Great. Now let’s just set the maximum iterations to 5000, in case of our code, howMuch would be 5000. This means that our loop starts at 1 and increases 0.01 every iteration until it reaches 5000.
The biggest clue that your program is running on a single Thread is checking the CPU performance diagram.
As you can see it is almost using 30% of the CPU, which is the sign that we are running on a single thread. And the amount of time this took is about 8 seconds:
Please note that on your machine, this will vary depending on your processor speed.
Now let’s convert this code to Parallel. The first thing that I should point out is that regular For is a keyword and Parallel.For is a function call!. This function has 12 overloads! the simplest one that we are going over in this introduction is similar to a regular for:
The first argument is the start of the counter, the 2nd one is the end number, which in case of int, it will be incremented one by one, for example, Parallel.For(1, 100, ….) will run 99 tasks in parallel, (the to is exclusive, but from is inclusive) and the 3rd argument is the body of the loop as Action.
The more advanced For function call will look like this:
Ok, now let’s convert our simple for loop to a Parallel.For:
Huh, Pretty simple. The only thing that changes is how we initialize the For loop, the rest of the code in the body did not change at all!
Let’s see the performance now,
WOW!, that’s almost 8 times faster! and we only changed 2 lines of code. Using Parallel instead of sequential, if there is ONLY CPU involved, is usually 6 to 8 times faster. but if for example you are reading the content of all the files in a folder, and counting how many times a word is repeated, there are other factors to consider, besides CPU computations, you will have File Access, if the files are on a network driver, then Network performance should also be considered.
Now if you see the CPU graph, you should see you are using 100% of the CPU
This simple call can boost the performance of your application many folds, but there are couple of things that you should consider:
- First, this example was super simple, you can do more interesting things, like knowing the state of the loop, and running the iterations in parallel.
- The second point is if you have a break; in your normal loop, that would not work in the parallel world. There is no context to break out of, instead, you would use return; this will return from the thread and release it to be used for another iteration.
- The third point is that the result of the order of execution is not always sorted from 1 up, meaning if you have a loop that is doing 10 iterations, iteration 9 might finish before iteration 2, and iteration 3 might be the last one!
I showed Parallel.For here, but Paralel.ForEach is a similar idea/syntax, but Parallel.Invoke is a little different in that regard that it will take an array of Actions, and runs them in parallel.
When you run this code, the results are NOT in the same order because it ran in parallel, as mentioned above, whichever Thread finishes first, will print the results. so you might get:
Third... First... Second...
and next time you run it, it might be:
First... Third... Second...
I hope this brief introduction was enough to get you excited and dig deeper into the Parallel world.
Source code: Download ParallelExample.cs
If you don’t have pluralsight, I recommend checking it out, it is a great learning tool.