我不确定这个问题是否只与Delphi有关,但这是我所使用的,所以我将参考它。
有人告诉我,即使从通常实现的线程池中启动一个新线程也要花费大约20-40ms。我在https://docs.microsoft.com/en-us/windows/desktop/procthread/multitasking看到过一篇文章,该文章基本上说Windows中的时间片约为20毫秒,因此实际上最小线程执行时间为20毫秒。
我已经写了下面的代码,这是非常基本的。在设置有2个处理器,每个处理器1个内核的VMWare工作站VM中,该时序报告大约需要17毫秒才能完成。
当我在主机上运行它时(i7-6700),秒表始终报告0毫秒以完成。有人告诉我我在主机上使用WaitFor感到很“幸运”,通常我应该为单个线程等待20毫秒。显然,这意味着无法将线程执行时间降低到20ms以下。
关于启动线程需要多长时间有确切的解释?
我用于测试的代码如下。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyThread=class(TThread)
public
Sum:integer;
procedure Execute;override;
end;
var
Form1: TForm1;
implementation
uses
System.Diagnostics;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
sw:TStopWatch;
thrd: TMyThread;
theSum:integer;
begin
sw:=TStopWatch.StartNew;
thrd:=TMyThread.Create;
thrd.WaitFor;
theSum:=thrd.sum;
thrd.Free;
sw.Stop;
memo1.lines.add('sum: '+theSum.ToString);
memo1.lines.add('elapsed: '+sw.ElapsedMilliseconds.toString);
end;
{ TMyThread }
procedure TMyThread.Execute;
var
cntr: Integer;
begin
inherited;
sum:=0;
for cntr := 0 to 100 do
sum:=sum+cntr;
end;
end.
答案 0 :(得分:0)
在Win10 x64,i5 6500,Delphi Rio上使用以下代码,我能够获得的最快速度为14-16毫秒:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyThread = class(TThread)
public
procedure Execute; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
M: TMyThread;
S, L: Int64;
begin
QueryPerformanceCounter(S);
M := TMyThread.Create;
M.WaitFor;
QueryPerformanceCounter(L);
Label1.Caption := IntToStr(L - S);
M.Free;
end;
{ TMyThread }
procedure TMyThread.Execute;
begin
inherited;
end;
end.
这完全是关于操作系统时间片的。即使在具有并行执行的多核/ 超线程系统上,理论上线程启动时间接近零,上下文切换为零,并且线程更早终止,您也可以在下一个时间片中达到它。
多个短任务可以在一个线程中的一个时间片中执行。
如果有多个短操作,但线程初始化需要一些时间,线程池对于立即获取初始化线程很有用。
在OS中,切片时间在上下文切换时间成本和响应度之间得到了很好的平衡。即使there are ways to decrease it到1ms-0.5ns,如果硬件体系结构允许,较低的切片时间也不总是更好。
编辑:某些技术(例如Intel Hyper-Threading)允许在同一时间段内在同一内核上的多个线程上执行,请参见注释。
答案 1 :(得分:0)
使用Delphi对短线程应用程序进行计时可能会产生误导,因为大多数人习惯于在IDE中进行此类计时。如果您在IDE中运行,则线程启动会很慢,如本文所述,大约20-40毫秒。这可能是因为在IDE中运行时,会向“消息”发送有关线程启动和停止的文本,这些文本可能与主IDE线程同步。
我本人和其他人在许多计算机上在IDE外面计时似乎表明,在Windows上,线程的创建/销毁需要0.1到0.4毫秒,具体取决于计算机。当然,请在您自己的目标计算机上进行测试以进行确认。只需确保在IDE外部进行测试即可。
然后,线程池在Delphi中发挥作用。第一,它们可以在IDE内进行调试时极大地加快内部时序。另外,根据线程池,我获得了0.01毫秒的任务启动时间来启动任务。因此,对于线程化时仅花费1-2毫秒的短暂时间,缩短任务启动时间的好处就很有意义。
但是,对于大多数人来说,线程运行时间超过20毫秒左右,使用线程池可能带来的好处微不足道。