Tutorial: Verwenden der For-Schleife aus der Parallel Programming Library

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Tutorials zur Parallel Programming Library

In diesem Tutorial wird die Verwendung der Methode TParallel.For aus der Parallel Programming Library (PPL) gezeigt. TParallel.For teilt eine for-Schleife in einzelne Teile auf, die parallel ausgeführt werden, und führt diese Teile mit Aufgaben aus.

Dieses Tutorial besteht aus einer einfachen Anwendung, die die ersten X Primzahlen sucht. Diese Berechnung wird mit einer seriellen Version mit der klassischen for-Schleife und einer parallelen Version mit der Methode TParallel.For durchgeführt.

Erstellen des Projekts

Erstellen Sie ein neues Projekt:

  • Für Delphi wählen Sie Datei > Neu > Geräteübergreifende Anwendung - Delphi > Leere Anwendung.
  • Für C++Builder wählen Sie Datei > Neu > Geräteübergreifende Anwendung - C++Builder > Leere Anwendung.

Hinzufügen der Komponenten

  1. Fügen Sie dem Formular zwei TButton-Komponenten hinzu.
    • Setzen Sie die Eigenschaft Name einer Schaltfläche auf btnForLoop und die Eigenschaft Text auf For Loop. Mit dieser Schaltfläche wird die serielle Version der Primzahlberechnung aufgerufen.
    • Setzen Sie die Eigenschaft Name der anderen Schaltfläche auf btnParallelLoop und die Eigenschaft Text auf Parallel Loop. Mit dieser Schaltfläche wird die parallele Version der Primzahlberechnung aufgerufen.
  2. Legen Sie eine TMemo-Komponente auf dem Formular ab.
    • Passen Sie die Größe von TMemo so an, dass die gesamten Meldungen angezeigt werden können.

Implementieren der TParallel.For-Funktionalität

Implementieren Sie zuerst die Ereignisbehandlungsroutinen für die OnClick-Ereignisse der Schaltflächen For Loop und Parallel Loop. Mit der Schaltfläche For Loop wird die Funktion ausgeführt, die nach den Primzahlen mit einer klassischen for-Schleife sucht. Parallel Loop verwendet TParallel.For.

Schreiben Sie dazu Code wie den folgenden:

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 wird die Funktion als anonyme Methode an TParallel.For übergeben.

Fügen Sie auch den Implementierungscode für die Funktion IsPrime hinzu:

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++ wird die Funktion als Iterator-Ereignis an TParallel.For übergeben.

Der Code zur Implementierung des Iterator-Ereignisses:

void __fastcall TForm1::MyIteratorEvent(TObject* Sender, int AIndex)
{
	if(IsPrime(AIndex)){
		TInterlocked::Increment(Tot);
	}
}

Der Code für die Funktion IsPrime in C++:

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;
	}
}

Fügen Sie auch die folgenden Deklarationen in die Projekt-Header-Datei ein:

private:	// User declarations
	void __fastcall MyIteratorEvent(TObject* Sender, int AIndex);
public:     // User declarations
       int Tot;

Sie müssen auch die erforderlichen Bibliotheken in den Code einbeziehen.

Delphi:

Fügen Sie für Delphi-Anwendungen der uses-Klausel die folgende Unit hinzu, sofern sie noch nicht darin enthalten ist:

uses
  System.Threading;
  System.Diagnostics;
  System.SyncObjs;
C++:

Fügen Sie für C++-Anwendungen der Projekt-Header-Datei den folgenden include-Operator hinzu:

#include <System.Threading.hpp>
#include <System.Diagnostics.hpp>
#include <System.SyncObjs.hpp>

Ausführen der Anwendung

Nun können Sie die Anwendung ausführen:

  • Drücken Sie F9, oder wählen Sie Start > Start.
    Forlooptutorial.png

Wie Sie sehen, ist die Methode TParallel.For effizienter, weil sie die verfügbaren CPUs für die parallele Ausführung von Prozeduren verwendet.

Siehe auch