2017-06-09 6 views
2

同じジョブを実行するマルチスレッドコードの2つの方法があります。TThreadより遅いTTask

TTask:

const 
    MaxThreadCount = 80; 

procedure TWorkerTask.Update; 
var 
    aTasks : array of ITask; 
    I: Integer; 
begin 
    Stopwatch := TStopwatch.StartNew; 
    SetLength(aTasks, MaxThreadCount); 
    for I := Low(aTasks) to High(aTasks) do begin 
    aTasks[I] := TTask.Create(procedure 
    begin 
     Writeln('Thread ', TTask.CurrentTask.Id, ' Stared'); 
     Sleep(5000); 
     Writeln('Thread ', TTask.CurrentTask.Id, ' Finshed'); 
    end); 
    aTasks[I].Start; 
    end; 
    TTask.WaitForAll(aTasks); 
    Elapsed := Stopwatch.Elapsed; 
    Writeln('Done in ', Round(Elapsed.TotalSeconds)); 
end; 

出力例えばDone in 29

のTThread:

const 
    MaxThreadCount = 80; 

procedure TWorker.Execute; 
begin 
    Writeln('Thread ', ThreadID, ' Stared'); 
    Sleep(5000); 
    Writeln('Thread ', ThreadID, ' Finshed'); 
end; 

.... 

var 
    Workers : array of TWorker; 
    I   : Integer; 
    Stopwatch : TStopwatch; 
    Elapsed : TTimeSpan; 
begin 
    SetLength(Workers, MaxThreadCount); 
    for I := Low(Workers) to High(Workers) do begin 
    Workers[I] := TWorker.Create; 
    Workers[I].Start; 
    end; 
    for I := Low(Workers) to High(Workers) do 
    Workers[I].WaitFor; 
    Elapsed := Stopwatch.Elapsed; 
    Writeln('Done ', Round(Elapsed.TotalSeconds)); 

出力例えばDone 8

Q:TTaskは上TThreadクラスより極端に遅いのはなぜ上記の方法?同様の結果を得るためにスピードアップする方法はありますか?

+1

出力がコードと一致しません。 *実際の出力とは何ですか? –

+0

@RemyLebeauの出力が編集されました – RepeatUntil

+0

@RepeatUntilもしあなたがそれを使用しないなら、 'Writeln( 'Thread'、ThreadID、 'Stared');などをコーディングするのは何ですか?注:これらの行の出力は、何が起こっているのかを理解するのに役立ちます(特に出力にタイムスタンプを含める場合)。 –

答えて

8

スレッドとタスクが機能しないためです。

プロセッサよりもスレッド数が多いです。スレッドを使用しているバージョンでは、タスクごとに1つのスレッドを作成できますが、プロセッサはオーバーサブスクライブされていますが、スレッドがスリープしているので問題はありません。

タスクベースのバージョンには、通常、プロセッサごとに1つのスレッドがあります。したがって、すべてのタスクを同時に実行できるわけではありません。

CPUをフル稼働している忙しい作業とスリープを交換する場合、両方のバージョンが同じように動作することがわかります。実際、私はプロセッサをオーバーサブスクライブしないので、タスクベースのバージョンがより良くなると期待しています。

+0

同様に?本気ですか?私は、TTaskの実装がどのようになっているのか分かりません(あなたが説明したところからは、CPUコアに従って作業を分散しているようですが)80スレッドを作成するのは本当のオーバーヘッドです(コンテキスト切り替えが効率的でなければならない)。 Delphiがネイティブスレッドプールを実装していれば、よりうまくいくはずですが、私が知る限り、そうはしません。 – Victoria

+0

はい、私は確信しています。 80スレッド以上のオーバーヘッドは、5秒間の睡眠と比較して些細なものです。 –

+0

私は公平なコンテキストの切り替えを信じていますが、実際にはサーバー以外のパラレルに80スレッドを持つ実際の使用は何ですか(多くのマシンに配布される重いコンピューティングを除く)?その場合、私はネイティブスレッドプールAPIの実装やキューを考えるのではなく、非常に多くのスレッドを作成しています。 'TTask'がパフォーマンスの優位性をもたらすかどうかは間違いなく考えています。もちろん、睡眠は問題です(したがって、ベンチマークは間違っています)。 – Victoria