チュートリアル:並列プログラミング ライブラリの for ループを使用する

提供: Appmethod Topics
移動先: 案内検索

並列プログラミング ライブラリ関連のチュートリアル への移動

このチュートリアルでは、並列プログラミング ライブラリ(PPL)TParallel.For メソッドの使い方を説明します。TParallel.For は、for ループを並列に動作する複数の部分に分割し、タスクを使って個々の部分を実行します。

このチュートリアルでは、最初の X 個の素数を探す簡単なアプリケーションを作成します。この計算は、従来の for ループを使った順次処理と、TParallel.For メソッドを使った並列処理で行います。

プロジェクトの作成

新規プロジェクトを作成します。

  • Object Pascal の場合は、[ファイル|新規作成|マルチデバイス アプリケーション - Object Pascal|空のアプリケーション]を選択します。
  • C++ の場合は、[ファイル|新規作成|マルチデバイス アプリケーション - C++|空のアプリケーション]を選択します。

コンポーネントの追加

  1. フォームに TButton コンポーネントを 2 つ追加します。
    • 1 つのボタンの Name プロパティを「btnForLoop」に、Text プロパティを「For Loop」に設定します。このボタンは、順次処理の素数計算を開始するためのものです。
    • もう 1 つのボタンの Name プロパティを「btnParallelLoop」に、Text プロパティを「Parallel Loop」に設定します。このボタンは、並列処理の素数計算を開始するためのものです。
  2. フォームに TMemo をドロップします。
    • メッセージ全体を表示できるよう、TMemo のサイズを調整します。

TParallel.For 機能の実装

まず、[For Loop]ボタンおよび[Parallel Loop]ボタンの OnClick イベントのイベント ハンドラを実装します。[For Loop]ボタンは、従来の for ループを使って素数を探す関数を実行するためのものです。[Parallel Loop]では TParallel.For を使用します。

次のコードを記述します。

Object Pascal の場合:

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;

Object Pascal では、関数が無名メソッドとして TParallel.For に渡されます。

また、IsPrime 関数の実装コードも追加する必要があります。

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

}

C++ では、関数がイテレータ イベントとして TParallel.For に渡されます。

このイテレータ イベントの実装コードは次のとおりです。

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

C++IsPrime 関数のコードは次のとおりです。

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

さらに、次の宣言をプロジェクト ヘッダー ファイルに追加します。

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

また、必要なライブラリをコードに含める必要があります。

Object Pascal の場合:

Object Pascal アプリケーションの場合、次のユニットが uses 句に含まれていなければ追加します。

uses
  System.Threading;
  System.Diagnostics;
  System.SyncObjs;

C++ の場合: C++ アプリケーションの場合、プロジェクト ヘッダー ファイルに以下の #include を追加します。

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

アプリケーションの実行

この時点で、アプリケーションを実行することができます。

  • F9 キーを押すか、[実行|実行を選択します。
    Forlooptutorial.png

TParallel.For がどれだけ効率がいいかが見てとれます。これは、利用可能な CPU を使って手続きを並列で実行しているためです。

関連項目