CrossKylix でコンパイルできるサーバー部分を持つ Delphi 7 でアプリケーションを管理しています。パフォーマンスの問題については、マルチスレッドとクリティカル セクションの使用をベンチに置いています。
100 個の TThread を作成し、各 TThread がフィボナッチを計算するコンソール アプリケーションを作成しました。次に、クリティカル セクションを追加して、一度に 1 つのスレッドだけがフィボナッチを計算するようにします。予想どおり、クリティカル セクションを使用しない方がアプリケーションは高速です。
次に、100 個の TThread を作成し、各 TThread がローカルの TStringList に単語を追加し、その TStringList をソートするコンソール アプリケーションを作成しました。次に、クリティカル セクションを追加して、一度に 1 つのスレッドのみが実行されるようにします。Windows では、予想どおり、アプリケーションはクリティカル セクションがなくても高速に実行されます。Linux では、CriticalSection バージョンは Critical Section のないバージョンよりも 2 倍高速に実行されます。
Linux の CPU は 6 コアの AMD Opteron であるため、アプリはマルチスレッドの恩恵を受けるはずです。
クリティカル セクションを含むバージョンの方が速い理由を誰か説明できますか?
編集(コードを追加)
スレッドの作成と待機
tmpDeb := Now;
i := NBTHREADS;
while i > 0 do
begin
tmpFiboThread := TFiboThread.Create(true);
tmpFiboThread.Init(i, ParamStr(1) = 'Crit');
Threads.AddObject(IntToStr(i), tmpFiboThread);
i := i-1;
end;
i := 0;
while i < NBTHREADS do
begin
TFiboThread(Threads.Objects[i]).Resume;
i := i+1;
end;
i := 0;
while i < NBTHREADS do
begin
TFiboThread(Threads.Objects[i]).WaitFor;
i := i+1;
end;
WriteLn('Traitement total en : ' + inttostr(MilliSecondsBetween(Now, tmpDeb)) + ' milliseconds');
TThread および Critical セクションの使用
type TFiboThread = class(TThread)
private
n : Integer;
UseCriticalSection : Boolean;
protected
procedure Execute; override;
public
ExecTime : Integer;
procedure Init(n : integer; WithCriticalSect : Boolean);
end;
var
CriticalSection : TCriticalSection;
implementation
uses DateUtils;
function fib(n: integer): integer;
var
f0, f1, tmpf0, k: integer;
begin
f1 := n + 100000000;
IF f1 >1 then
begin
k := f1-1;
f0 := 0;
f1 := 1;
repeat
tmpf0 := f0;
f0 := f1;
f1 := f1+tmpf0;
dec(k);
until k = 0;
end
else
IF f1 < 0 then
f1 := 0;
fib := f1;
end;
function StringListSort(n: integer): integer;
var
tmpSL : TStringList;
i : Integer;
begin
tmpSL := TStringList.Create;
i := 0;
while i < n + 10000 do
begin
tmpSL.Add(inttostr(MilliSecondOf(now)));
i := i+1;
end;
tmpSL.Sort;
Result := StrToInt(tmpSL.Strings[0]);
tmpSL.Free;
end;
{ TFiboThread }
procedure TFiboThread.Execute;
var
tmpStr : String;
tmpDeb : TDateTime;
begin
inherited;
if Self.UseCriticalSection then
CriticalSection.Enter;
tmpDeb := Now;
tmpStr := inttostr(fib(Self.n));
//tmpStr := inttostr(StringListSort(Self.n));
Self.ExecTime := MilliSecondsBetween(Now, tmpDeb);
if Self.UseCriticalSection then
CriticalSection.Leave;
Self.Terminate;
end;
procedure TFiboThread.Init(n : integer; WithCriticalSect : Boolean);
begin
Self.n := n;
Self.UseCriticalSection := WithCriticalSect;
end;
initialization
CriticalSection := TCriticalSection.Create;
finalization
FreeAndNil(CriticalSection);
編集 2
このWhy-using-more-threads-makes-it-it-slower-than-using-less-threadsを読んだので、これを理解しているように、コンテキスト切り替えは、win32でのコンテキスト切り替えよりも、LinuxとKylixコンパイルでより多くのCPUリソースを消費します。