2010-12-08 34 views

cevap

11

Muhtemelen en iyi çözüm, OmniThreadLibrary numaralı telefondaki Paralel For Loop yapısıdır. Bir koleksiyon veya alt ve üst sınırları temsil eden bir çift tamsayı ve döngü gövdesini temsil eden anonim bir yöntem iletirsiniz ve for döngüsünü paralel olarak çalıştırmak için bir iş parçacığı havuzu kullanır.

Bunun yalnızca döngü gövdesi yöntemi kendi kendine ayakta durabiliyorsa çalışacağını unutmayın. Herhangi bir dış değişkeni değiştirirse veya döngüde daha önce yapılan bir hesaplama değerine dayanıyorsa, paralelleştirilemez.

Paralel olarak OmniThreadLibrary için bir giriş here bulunabilir. Örneğin, sayıların üzerinde döngü iterating için basit şuna benzer:

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

Bu harika görünüyor. –

+0

OmniThreadLibrart kullanarak paralel döngü gerçekleştirme örneği gönderebilir mi? Ya da örneğin – Astronavigator

+0

@Astronavigator'a bağlantı: Örnekler için son paragraftaki bağlantıya bakın. –

0

Paralel döngü ve uygulama/uygulama ile ne demek istediğinize bağlıdır.

TThread ve TMultiReadExclusiveWriteSynchronizer'a bir göz atın.

+0

Ben bir şeye benziyorum [parallel for i: = 1 to 10 do MyProc (i); ] veya belki bir şey gibi [ParallelDo (i, 1,10, MyProc)] – Astronavigator

4

Eğer bu kodu kullanabilirsiniz ParallelFor sadece gerekirse: Daha parçacığı "şeyler" gerekirse, Ancak

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; 

seni Üçüncü parti kütüphaneleri kullanmayı düşünmelidir.

+0

Oldukça karmaşık bir çözüm ... – Astronavigator

+1

Sizin için ne kadar karmaşık? Bu çok basit bir çözüm IMO. OmniThreadLibrary kullanmanın çok daha basit. Şöyle bir şey yazabilirsiniz: ParallelFor (0, Sayım - 1, prosedür (i: Tamsayı; ThreadID: Tamsayı), bir şeyler yapmaya başlar. – Linas

+4

Bence bir kütüphane çözümü (Omni bariz bir seçimdir) bazı avantajlara sahiptir. Bu kodun başlangıcı için, amaçlanan hiçbir ihlal, performans sorunları vardır. ParallelFor'u her aradığınızda parçacıkları oluşturmak ve yok etmek pahalıdır. Daha iyi bir havuz gitmek için hazır bekliyor. Bir döngüde WaitFor'u çağırmak da bir hatadır, Win32'daki birden çok nesne bekleme işlevlerinden birini kullanmalısınız. Kritik bölüm savurganlıktır - kilitli artış daha iyidir. Bu görevler küçük olduğunda önemli sorunlar olabilir. Ayrıca önemli bir ihmal olan istisnalar ele alınmamaktadır. –