我正在尝试评估并发线程的速度。我不明白结果。就像某个地方有一个锁。我正在Dell 3571上运行以下代码,20核/线程i9:
1.机组1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TMyThread = class(TTHread)
public
procedure Execute; override;
end;
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure Log(Sender: TMyThread; Log: string);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Log(Sender: TMyThread; Log: string);
begin
Memo1.Lines.add(Log);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Thr: array[0..19] of TMyThread;
begin
for var t := 0 to 10 do
begin
var Thread := TMyThread.Create(True);
Thr[t] := Thread;
Thread.Priority := TPHigher;
end;
for var t := 0 to 10 do
Thr[t].Resume;
end;
{ MyThread }
procedure TMyThread.Execute;
begin
sleep(500);
try
var ii: nativeint;
var Start := GetTickCount;
for var i := 0 to 750000000 do
inc(ii);
var Delta := (GetTickCount - Start);
Synchronize( procedure begin Form1.Log(Self, Format( 'Done Loading : %dms', [Delta]) ); end );
except
asm nop; end;
end;
end;
end.
在使用1个线程运行此程序时,我得到:320毫秒一次计算当运行这个与10 theand,我得到:
Done Loading : 344ms
Done Loading : 375ms
Done Loading : 391ms
Done Loading : 422ms
Done Loading : 438ms
Done Loading : 469ms
Done Loading : 469ms
Done Loading : 469ms
Done Loading : 516ms
Done loading : 531ms
所有结果在320 ms时是否几乎相同?
PS:我试过用windows CreatThread,ITask...同样的结果,无论线程的数量...
有什么想法吗?谢谢。
2条答案
按热度按时间ctrmrzij1#
您正在启动10个线程(除了运行应用程序的主线程),但除了将优先级设置为“更高”之外,您没有告诉Windows任何有关调度它们的信息。“更高”线程优先级所能确定的是,当Windows调度程序在CPU/内核上分配时间片时,您的10个线程都具有相同的优先级。
除非另有说明,否则调度程序将考虑许多因素,以确定在任何给定时间点在哪个内核/CPU上调度任何线程。
因此,每个线程可能发现自己在每个时间片上从一个内核切换到另一个内核,每次都会导致相对昂贵的“上下文切换”。或者,它可能被调度到它已经在的同一个内核上。在同一个内核上一致调度的线程将比任何以大量上下文切换为开销进行相同工作的线程执行得“更好”。
为了确保线程一致地运行在同一个内核上,避免可能代价高昂的上下文切换,您需要设置每个线程的Processor Affinity。
但事情远比这复杂
虽然您可以设法将每个线程安排在一个单独的、一致的内核上,但您无法(如此容易地)确定Windows决定在每个内核上安排哪些其他任务,因此表面上执行相同工作的线程之间的性能仍会存在一些差异,具体取决于分配给它们的内核也在执行哪些任务。
如果您正在着手一个项目,希望通过在一系列不同的硬件配置(双核/四核/六核/八核/多核系统)上执行线程来从系统中获得最大性能,请注意,线程的理想配置 * 将 * 因这些不同的配置而异。
当您开发由线程执行的真实的工作负载而不是合成的指标收集工作负载时,尤其如此。
您要么需要设计启发式技术来动态地调整配置,要么需要提供某种机制来手动配置软件以“调优”性能(或者两者兼而有之)。
xyhw6mcr2#
您的处理器是i9 12900H。它有6个性能内核和8个高效内核。性能内核速度快,但功耗低;高效内核速度慢,但功耗低得多。
这就意味着你没有一套对称的处理器。虽然英特尔可能希望你认为你有20个处理器,但你实际上只有6个快速处理器。所以我预测,如果你把程序改为运行6个线程,你会得到更接近你预期的结果。
即使考虑到所有这些,您仍然不能总是期望在真实的世界的应用程序中实现线性伸缩。您的代码是一个人工测试,内部循环可以完全用寄存器来实现。但是在真实的应用中,你可以期望代码使用主存储器。然后,为了实现线性扩展,你依赖于存储系统来有效地向处理器传送数据。这是否能够实现取决于程序和硬件的相互作用。