大多数应用程序运行时都在此函数中:
function Panorama(var Solutions: TSolutionDynArray): Integer;
var
I, J: Integer;
begin
Result := 0;
for I := Low(Solutions) to High(Solutions) do
with Solutions[I] do begin
Panorama := Level;
for J := Low(FPertinentPanoramas[I, Level])
to High(FPertinentPanoramas[I, Level]) do
if Level > Solutions[FPertinentPanoramas[I, Level, J]].Level then
Panorama := Panorama + 1
else
Panorama := Panorama - 1;
Result := Result + Panorama;
end;
end;
其中
TSolution = record
Level, Panorama: Integer;
end;
TSolutionDynArray = array of TSolution;
FPertinentPanoramas
是整数的多维数组(初始化一次,然后保持不变)I, J
的计算不依赖于任何其他I, J
--因此这个问题可以容易地并行化:只需添加参数LowSolutions
和HighSolutions
并修改循环以
for I := LowSolutions to HighSolutions do
例如:使用多线程1..250、251..500、501..750、751..1000代替1..1000
但是,不管什么原因,单线程总是比多线程快(线程创建一次,然后重用--ExecuteAnonymousThreads; Event.WaitFor;
):
type
TAnonymousThread = class(TThread)
private
FEvent: TEvent;
FProc: TProc;
protected
procedure Execute; override;
procedure SetProc(const Proc: TProc);
public
constructor Create(const Proc: TProc = nil);
property Proc: TProc write SetProc;
end;
var
AnonymousThreads: array of TAnonymousThread;
Event: TEvent;
procedure InitializeThreads(const N: Integer);
procedure ExecuteAnonymousThreads;
implementation
var
FCriticalSection: TCriticalSection;
FCounter: Integer;
procedure Counter;
begin
with FCriticalSection do begin
Acquire;
FCounter := FCounter - 1;
if FCounter = 0 then
Event.SetEvent;
Release;
end;
end;
constructor TAnonymousThread.Create(const Proc: TProc = nil);
begin
inherited Create;
FreeOnTerminate := True;
FEvent := TEvent.Create;
SetProc(Proc);
end;
procedure TAnonymousThread.Execute;
begin
while not Terminated do begin
FEvent.WaitFor;
FEvent.ResetEvent;
if Assigned(FProc) then
FProc;
Counter;
end;
end;
procedure TAnonymousThread.SetProc(const Proc: TProc);
begin
FProc := Proc;
end;
procedure InitializeThreads(const N: Integer);
var
I: Integer;
begin
Event := TEvent.Create;
FCriticalSection := TCriticalSection.Create;
SetLength(AnonymousThreads, N);
for I := Low(AnonymousThreads) to High(AnonymousThreads) do
AnonymousThreads[I] := TAnonymousThread.Create;
end;
procedure ExecuteAnonymousThreads;
var
I: Integer;
begin
FCounter := Length(AnonymousThreads);
Event.ResetEvent;
for I := Low(AnonymousThreads) to High(AnonymousThreads) do
AnonymousThreads[I].FEvent.SetEvent;
end;
一个显而易见的问题是,为什么多线程性能如此低下,有什么可以改进的吗?
编辑:
- 我以前尝试过使用非匿名线程,将Execute硬编码到函数中,但是没有明显的改进,所以我发布了更简单的匿名代码
- 虽然TParallel.For在函数循环中表现得很糟糕,但现在我在函数中**使用它已经得到了令人鼓舞的结果:
TParallel.For(Low(A), High(A),
procedure(I: Integer)
begin
Panorama(SolutionsPool[I]);
end);
1条答案
按热度按时间xtupzzrd1#
总的来说,我会回答这个问题:为什么一个线程比分成几个线程运行得快?处理器一次执行一个任务,不能同时执行两个任务。Windows也是,但它模拟了多线程。在我们看来,程序同时工作,实际上它们依次工作。你的线程不是同时运行,而是依次运行。条件:每个线程依次执行一个命令,您只需将流拆分为几个并在它们之间添加同步(我没有在你的代码中详细说明,这没有意义)无论你多么努力,你的代码至少会以相同的速度执行(非常值得怀疑)。更快-永远不会。如果你能做得更快,那么它可以在一个线程中实现(会更快)。如果我是你,我会尽量少做线程和它们之间的同步。在新书中,我没有看到对计算机操作的描述,在旧书中有描述。
英特尔处理器汇编语言Kip.R.欧文//第71页