Everyone knows that typically device / computers today have multiple CPU’s, even my phone has 4! But when it comes to programming to get full benefits of working across those cores its often been a little tricky or time consuming and extra code overhead to manage. Well… that is until now with Parallel Programming with Delphi!
Starting with Delphi, C++ Builder and RAD Studio XE7, there is a new library that simplifies the effort needed to get tasks running in parallel, aptly named the Parallel Programming Library.
The Parallel Programming Library lives within the System.Threading unit and is made up of a number of new helpful features that can be easily introduced into new and also existing projects. There are also loads of overloaded arguments for fine tuning and supporting C++ working with this as well as Object Pascal.
These features include a new Parallel for loop that is easy to uses, along side a number of more advanced features for running tasks, joining tasks, waiting on groups of tasks etc to process. Under the hood there is a thread pool that self tunes itself automatically (based on the load on the CPU’s).
To give you an idea about how easily this is to plug in, lets take a simple example where you want to work out if a number is a prime number.
function IsPrime (N: Integer): Boolean; var Test: Integer; begin IsPrime := True; for Test := 2 to N - 1 do if (N mod Test) = 0 then begin IsPrime := False; break; {jump out of the for loop} end; end;
The traditional way to loop and check for the number of prime numbers between 1 to X value would be to do something like this where each number is checked in sequence and the total stored into a variable (here Tot is an integer)
const Max = 50000; // 50K for I := 1 to Max do begin if IsPrime (I) then Inc (Tot); end;
Using the new Parallel library, this can be achieved by replaces the “for” command with a call to the class function TParallel.For passing in the code to be run as an anonymous method.
In addition, to avoid clashes with multiple threads running, you can call TInterlocked.Increment.
TParallel.For(1, Max, procedure (I: Integer) begin if IsPrime (I) then TInterlocked.Increment (Tot); end);
So what difference does this make?
Using TStopWatch from System.Diagnostics we are able to test the time to run each version of the loop above. Even on my VM running only 2 cores the time drops from 415ms for the standard for loop down to 192ms using the Parallel programming library version. On my Mac where there are more cores available it goes from 382ms down to 90ms for the same test!
What I love about this, is this is a really easy solution to plug into existing code as its part of the language and framework.
The great thing about writing native code is that we can take advantage of all the cores on a device. 🙂 Including Mobiles! However, as a word of caution, use it only where you need to on mobile as it will use more battery if you are running multiple threads heavily.
Samples
An other example that can help get your head around how to use the Parallel Programming library is a sample of Conways game of life for both Object Pascal and C++ in the samples directory shipped with XE7, located in the RTL samples. e.g.
C:\Users\Public\Documents\Embarcadero\Studio\15.0\Samples\Object Pascal\RTL\Parallel Library
C:\Users\Public\Documents\Embarcadero\Studio\15.0\Samples\CPP\RTL\Parallel Library
Not sure about you, but I’m off to speed up some processing in some old projects I have 🙂 Happy coding!
Thanks for nice example. The only thing that I would add is that it would be very inefficient to detect and count primes like this. I understand that it is only example but I think it is worth mentioning. And that leads to other question – there are some primitives for concurrent increasing etc. But are there any more complex primitives like semaphores or critical sections?
The nice thing is the Parallel programming library is at its core a really powerful implementation of Threads. So everything you would expect to use with Threads are available and should be used when working with Parallel programming libraries. Check out unit System.SyncObjs;