Tutorial: Using the For Loop from the Parallel Programming Library
Go Up to Parallel Programming Library Tutorials
Contents
This tutorial shows how to use the TParallel.For method from the Parallel Programming Library (PPL). TParallel.For splits a for loop into pieces that run in parallel and uses tasks to run those pieces.
This tutorial consists of a simple application that finds the first X
prime numbers. This calculation is done with a serial version using the classic for loop and a parallel version using the TParallel.For method.
Creating the Project
Create a new project:
- For Delphi, choose File > New > Multi-Device Application - Delphi > Blank Application.
- For C++Builder, choose File > New > Multi-Device Application - C++Builder > Blank Application.
Adding the Components
- Add two TButton components to the form.
- Set the Name property of one of the buttons to btnForLoop and its Text property to For Loop. This button will launch the serial version of the prime numbers calculation.
- Set the Name property of the other button to btnParallelLoop and its Text property to Parallel Loop. This button will launch the parallel version of the prime numbers calculation.
- Drop a TMemo to the form.
- Adjust the size of the TMemo to display the messages entirely.
Implementing the TParallel.For Functionality
First, implement the event handlers for the OnClick events of the For Loop and Parallel Loop buttons. The For Loop button runs the function that looks for prime numbers using a classic for loop. The Parallel Loop uses the TParallel.For.
For this, write code as follows:
Delphi:
const
Max =5000000;
procedure TForm1.btnForLoopClick(Sender: TObject);
var
I, Tot: Integer;
SW: TStopwatch;
begin
// counts the prime numbers below a given value
Tot:=0;
SW := TStopWatch.Create;
SW.Start;
for I := 1 to Max do
begin
if IsPrime(I) then
Inc(Tot);
end;
SW.Stop;
Memo1.Lines.Add(Format('Sequential For loop. Time (in milliseconds): %d - Primes found: %d', [SW.ElapsedMilliseconds,Tot]));
end;
procedure TForm1.btnParallelForClick(Sender: TObject);
var
Tot: Integer;
SW: TStopwatch;
begin
try
// counts the prime numbers below a given value
Tot :=0;
SW :=TStopWatch.Create;
SW.Start;
TParallel.For(2,1,Max,procedure(I:Int64)
begin
if IsPrime(I) then
TInterlocked.Increment(Tot);
end);
SW.Stop;
Memo1.Lines.Add(Format('Parallel For loop. Time (in milliseconds): %d - Primes found: %d', [SW.ElapsedMilliseconds,Tot]));
except on E:EAggregateException do
ShowMessage(E.ToString);
end;
end;
In Delphi, the function passes to the TParallel.For as an anonymous method.
You should also add the implementation code of the IsPrime
function:
function IsPrime(N: Integer): Boolean;
var
Test, k: Integer;
begin
if N <= 3 then
IsPrime := N > 1
else if ((N mod 2) = 0) or ((N mod 3) = 0) then
IsPrime := False
else
begin
IsPrime := True;
k := Trunc(Sqrt(N));
Test := 5;
while Test <= k do
begin
if ((N mod Test) = 0) or ((N mod (Test + 2)) = 0) then
begin
IsPrime := False;
break; { jump out of the for loop }
end;
Test := Test + 6;
end;
end;
end;
C++:
void __fastcall TForm1::btnForLoopClick(TObject *Sender)
{
int Max=5000000;
Tot =0;
System::Diagnostics::TStopwatch sw= System::Diagnostics::TStopwatch::Create();
sw.Start();
for(int I=1;I<=Max;I++){
if(IsPrime(I)) {
Tot++;
}
}
sw.Stop();
Memo1-> Lines->Add(
String().sprintf(L"Sequential For loop. Time (in milliseconds): %lld, Primes found: %lld",sw.ElapsedMilliseconds, Tot));
}
void __fastcall TForm1::btnParallelForClick(TObject *Sender)
{
int Max=5000000;
Tot =0;
System::Diagnostics::TStopwatch sw= System::Diagnostics::TStopwatch::Create();
sw.Start();
TParallel::For(NULL,1,Max,MyIteratorEvent);
sw.Stop();
Memo1-> Lines->Add(
String().sprintf(L"Parallel For loop. Time (in milliseconds): %lld, Primes found: %lld",sw.ElapsedMilliseconds, Tot));
}
In C++, the function passes to the TParallel.For as an Iterator Event.
The Iterator Event implementation code is as follows:
void __fastcall TForm1::MyIteratorEvent(TObject* Sender, int AIndex)
{
if(IsPrime(AIndex)){
TInterlocked::Increment(Tot);
}
}
The code for the IsPrime
function in C++ is:
bool TForm1::IsPrime(int N){
int Test, k;
bool aPrime;
if (N <= 3){
return N > 1;
}
else if (((N % 2) == 0) || ((N % 3) == 0)){
return false;
}else{
aPrime = true;
k = (int)sqrt(N);
Test = 5;
while (Test <= k){
if (((N % Test) == 0) || ((N % (Test + 2)) == 0)){
aPrime = false;
break; //jump out of the for loop
}
Test = Test + 6;
}
return aPrime;
}
}
Add also the following declarations to the project header file:
private: // User declarations
void __fastcall MyIteratorEvent(TObject* Sender, int AIndex);
public: // User declarations
int Tot;
You should also include the necessary libraries to the code.
Delphi:
For Delphi applications, add the following unit to the uses clause if they are not present:
uses
System.Threading;
System.Diagnostics;
System.SyncObjs;
C++:
For C++ applications, add the following include operator to the project header file:
#include <System.Threading.hpp>
#include <System.Diagnostics.hpp>
#include <System.SyncObjs.hpp>
Running the Application
At this point, you can now run the application:
- Press
F9
or choose Run > Run.
You can see how the TParallel.For is more efficient since it makes use of the available CPUs for running procedures in parallel.