Tutorial: Verwenden von Aufgaben aus der Parallel Programming Library

Aus Appmethod Topics
Wechseln zu: Navigation, Suche

Nach oben zu Tutorials zur Parallel Programming Library

In diesem Tutorial wird die Implementierung von Aufgaben aus der Parallel Programming Library (PPL) gezeigt. Aufgaben sind Arbeitseinheiten, die sich in einer Warteschlange befinden und gestartet werden, wenn CPU-Zeit verfügbar ist. Aufgaben können Operationen parallel ausführen. Ein Master-Thread verwaltet diese Warteschlange und weist Threads aus dem Thread-Pool zur Ausführung der Aufgaben zu. Die Anzahl der Threads dieses Thread-Pools ist von der Anzahl der verfügbaren CPUs abhängig.

Erstellen des Projekts

Erstellen Sie ein neues Projekt:

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

Hinzufügen der Komponenten

  1. Fügen Sie dem Formular eine TButton- und eine TLabel-Komponente hinzu. Mit TButton wird eine Aufgabe gestartet und in TLabel werden die Ergebnisse angezeigt.
  2. Ziehen Sie eine TScrollBar-Komponente auf das Formular.
  3. Legen Sie eine TFloatAnimation-Komponente auf dem Formular ab.
    • Legen Sie die Komponente TFloatAnimation als der Bildlaufleiste untergeordnet fest Die Struktur der Komponenten sollte folgendermaßen aussehen:
    Structure task.png
    • Setzen Sie die Eigenschaft AutoReverse auf True.
    • Setzen Sie die Eigenschaft Duration auf 1 Sekunde.
    • Setzen Sie die Eigenschaft Enabled auf True.
    • Setzen Sie die Eigenschaft Loop auf True.
    • Setzen Sie die Eigenschaft PropertyName auf Value.
    • Setzen Sie die Eigenschaft StartValue auf 0 und die Eigenschaft StopValue auf 100.

Implementieren der Ereignisbehandlungsroutinen für die Komponenten

Implementieren Sie zuerst die Ereignisbehandlungsroutine für das Ereignis OnClick von TButton. Schreiben Sie dazu Code wie den folgenden:

Object Pascal:
procedure TForm1.Button1Click(Sender: TObject);
var
  lValue: Integer;
begin
    Label1.Text := '--';
    {Some calculation that takes time}
    Sleep(3000);
    lValue := Random(10);
    Label1.Text := lValue.ToString;
end;
end.
C++:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	int lValue;
	Label1->Text = "--";
	//{Some calculation that takes time}
	Sleep(3000);
	lValue = Random(10);
	Label1->Text = String(lValue);

}

Dieser Code ist ein Beispiel für eine lange Berechnung, die beginnt, wenn Sie auf die Schaltfläche drücken. Es wird 3 Sekunden gewartet und dann eine Zahl zwischen 0 und 10 angezeigt.

Ausführen der Anwendung ohne PPL-Implementierung

Nun können Sie die Anwendung ausführen:

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

Die Bildlaufleiste bewegt sich von rechts nach links. Sobald Sie jedoch auf die Schaltfläche drücken und die lange Berechnung beginnt, wird die Bildlaufleiste angehalten, bis die Berechnung beendet ist. Offensichtlich ist dies nicht das erwartete Verhalten. Im nächsten Abschnitt wird gezeigt, wie Sie dieses Verhalten mit der TTask-Funktionalität der PPL verbessern können.

Implementieren der TTask-Funktionalität

In diesem Abschnitt wird gezeigt, wie Sie die lange Berechnung (die als OnClick-Ereignis implementiert ist) in eine TTask einbetten, damit dieser Prozess parallel ausgeführt werden kann.

Benennen Sie zunächst im Anwendungsformular die Komponenten TButton und TLabel in ButtonTask1 bzw. LabelTask1 um.

Beziehen Sie anschließend die PPL-Bibliothek in das Projekt ein:

Fügen Sie für Object Pascal-Anwendungen der uses-Klausel die folgende Unit hinzu, sofern sie noch nicht darin enthalten ist:
uses
  System.Threading;
Fügen Sie für C++-Anwendungen der Projekt-Header-Datei den folgenden include-Operator hinzu:
#include <System.Threading.hpp>

Für die Ausführung der Berechnung als Aufgabe stellt die PPL die Methode TTask.Run bereit. Ändern Sie den Code folgendermaßen:

Object Pascal:
procedure TForm1.ButtonTask1Click(Sender: TObject);
var
  lValue: Integer;
begin
    Label1.Text := '--';
    TTask.Run(procedure
      begin
          {Some calculation that takes time}
          Sleep(3000);
          lValue := Random(10);
          TThread.Synchronize(nil,
            procedure
            begin
                  Label1.Text := lValue.ToString;
            end);
      end);
end;

Im obigen Code wird aus den möglichen Eingabeparameteroptionen, die die Methode TTask.Run in Object Pascal bereitstellt, eine anonyme Methode für die lange Berechnung verwendet.

C++:

Beziehen Sie auch den Code für die Klassen TCppSync und TCppTask ein:

class TCppSync : public TCppInterfacedObject<TThreadProcedure> {
	int &lValue;
	TLabel *Label;
public:
	TCppSync(int &l, TLabel *lbl):lValue(l),Label(lbl)
	{}
	void __fastcall Invoke(){
	   Label->Text = String(lValue);
	}
};
 class TCppTask : public TCppInterfacedObject<TProc> {
	 int &lValue;
	 TLabel *Label;
 public:
	TCppTask(int &l, TLabel *lbl): lValue(l), Label(lbl)
	{}
	void __fastcall Invoke(){
		Sleep(3000);
		lValue = Random(10);
		TThread::Synchronize(0,_di_TThreadProcedure(new TCppSync(lValue, Label)));
	}
 };
void __fastcall TForm1::ButtonTask1Click(TObject *Sender)
{
	LabelTask1->Text = "--";
	TTask::Run(_di_TProc(new TCppTask(lValue, LabelTask1)));
}

Fügen Sie die Deklaration von lValue in den private-Abschnitt der Header-Datei ein:

private:	// User declarations
	int lValue;

Im obigen Code wird aus den möglichen Eingabeparameteroptionen, die die Methode TTask.Run in C++ bereitstellt, ein TProc-Typ für die lange Berechnung verwendet.

Ausführen der Anwendung mit der TTask-Funktionalität

Nun können Sie die Anwendung ausführen:

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

Wenn Sie jetzt ButtonTask1 drücken, bleibt die Bildlaufleisten-Aktion aktiv und wird nicht unterbrochen. Mit der TTask-Funktionalität der PPL können Sie mehrere Aufgaben parallel ausführen.

Siehe auch