2010-12-08 6 views

答えて

11

おそらく、現時点で最善の解決策は、並列ループの構文がOmniThreadLibraryであることでしょう。コレクション、または下限と上限を表す整数の組と、ループ本体を表す匿名メソッドを渡します。スレッドプールを使用して、forループを並列に実行します。

これは、ループボディメソッドが単独で機能することができる場合にのみ機能することに注意してください。外部変数を変更したり、ループの初期に行われた計算の値に依存したりすると、並列化できません。

omniThreadLibrary parallel forの紹介はhereです。あなたはこのコードを使用することができますParallelForのみが必要な場合

Parallel.ForEach(1, testSize).Execute(
    procedure (const elem: integer) 
    begin 
    // do something with 'elem' 
    end); 
+0

これはクールだ。 –

+0

OmniThreadLibrartを使用した並列ループ実現の例を掲載できますか?例: – Astronavigator

+0

@Astronavigatorへのリンク:例については、最後の段落のリンクを参照してください。 –

0

並列ループとアプリケーション/実装の意味によって異なります。

TThreadとTMultiReadExclusiveWriteSynchronizerを見てください。

+0

私は[私のための並列:1〜10はMyProc(i)を行うようなものです。 ]または多分[ParallelDo(i、1,10、MyProc)]のようなもの – Astronavigator

4

:たとえば、数字を反復ループのためのシンプルな、このようになります

interface 

uses 
    Classes, SysUtils; 

type 
    TParallelProc = reference to procedure(i: Integer; ThreadID: Integer); 

    TParallel = class(TThread) 
    private 
    FProc: TParallelProc; 
    FThreadID: Integer; //current thread ID 
    protected 
    procedure Execute; override; 
    function GetNextValue: Integer; 
    public 
    constructor Create; 
    destructor Destroy; override; 

    property Proc: TParallelProc 
     read FProc write FProc; 
    class var 
     CurrPos: Integer; //current loop index 
     MaxPos: Integer; //max loops index 
     cs: TCriticalSection; 
     ThCount: Integer; //thread counter - how much threads have finished execution 
    end; 


{** ParallelFor Loop - all iterations will be performed in chosen threads 
@param nMin - Loop min value (first iteration) 
@param nMax - Loop max value (last iteration) 
@param nThreads - how much threads to use 
@param aProc - anonymous procedure which will be performed in loop thread 
} 
procedure ParallelFor(nMin, nMax, nThreads: Integer; aProc: TParallelProc); overload; 
{** ParallelFor Loop - all iterations will be performed in max cpu cores 
@param nMin - Loop min value (first iteration) 
@param nMax - Loop max value (last iteration) 
@param aProc - anonymous procedure which will be performed in loop thread 
} 
procedure ParallelFor(nMin, nMax: Integer; aProc: TParallelProc); overload; 

implementation 

uses 
    {$IFDEF MSWINDOWS} 
    Windows, 
    {$ENDIF} 
    SyncObjs; 

procedure ParallelFor(nMin, nMax, nThreads: Integer; aProc: TParallelProc); 
var 
    threads: array of TParallel; 
    I: Integer; 
begin 
    if nMin > nMax then 
    Exit; 
    // initialize TParallel class data 
    TParallel.CurrPos := nMin; 
    TParallel.MaxPos := nMax; 
    TParallel.cs := TCriticalSection.Create; 
    TParallel.ThCount := 0; 

    // create the threads 
    SetLength (threads, nThreads); 
    for I := 0 to nThreads - 1 do 
    begin 
    threads[I] := TParallel.Create; // suspended 
    threads[I].FThreadID := I; 
    threads[I].Proc := aProc; 
    threads[I].Start; 
    end; 

    for I := 0 to nThreads - 1 do 
    begin 
    threads[I].WaitFor; 
    end; 

    for I := 0 to nThreads - 1 do 
    begin 
    threads[I].Free; 
    end; 

    TParallel.cs.Free; 
end; 

procedure ParallelFor(nMin, nMax: Integer; aProc: TParallelProc); 
begin 
    ParallelFor(nMin, nMax, CPUCount, aProc); 
end; 

{ TParallel } 

constructor TParallel.Create; 
begin 
    inherited Create(True); // suspended 
    InterlockedIncrement(ThCount); 
    FreeOnTerminate := False; 
    FThreadID := 0; 
end; 

destructor TParallel.Destroy; 
begin 
    InterlockedDecrement(ThCount); 
    inherited; 
end; 

procedure TParallel.Execute; 
var 
    nCurrent: Integer; 
begin 
    nCurrent := GetNextValue; 
    while nCurrent <= MaxPos do 
    begin 
    Proc(nCurrent, FThreadID); 
    nCurrent := GetNextValue; 
    end; 
end; 

function TParallel.GetNextValue: Integer; 
begin 
    cs.Acquire; 
    try 
    Result := CurrPos; 
    Inc(CurrPos); 
    finally 
    cs.Release; 
    end; 
end; 

をしかし、あなたはより多くのスレッドが必要な場合は、「もの」君サードパーティライブラリの使用を検討する必要があります。

+0

かなり複雑な解決策... – Astronavigator

+1

あなたはとても複雑ですか?それは非常に簡単なソリューションのIMOです。 OmniThreadLibraryを使用するよりもずっと簡単です。次のように書くことができます:ParallelFor(0、Count - 1、procedure(i:Integer; ThreadID:Integer)begin {do something} end); – Linas

+4

私はライブラリソリューション(オムニは明らかな選択肢です)はいくつかの利点があると思います。開始のために、このコードは意図された犯罪ではなく、パフォーマンス上の問題があります。 ParallelForを呼び出すたびにスレッドを作成して破棄するのは高価です。プールを準備するのを待つことをお勧めします。ループでWaitForを呼び出すのも間違いですが、Win32では複数のオブジェクト待機関数を一度使用する必要があります。クリティカルセクションは無駄です。インターロックされたインクリメントが優れています。これらは、タスクが小さい場合に重大な問題になる可能性があります。重要な省略である例外の処理もありません。 –