multithreading - Delphi中的线程启动速度
问题描述
我不确定这个问题是否只与 Delphi 相关,但这就是我使用的,所以我会提到它。
我被告知启动一个新线程,即使是从一个典型实现的线程池中也需要大约 20 - 40 毫秒。我参考了https://docs.microsoft.com/en-us/windows/desktop/procthread/multitasking上的文章,它基本上说 Windows 中的时间片约为 20 毫秒,所以实际上最小线程执行时间是20 毫秒。
我已经编写了下面的代码,这是非常基本的。在设置有 2 个处理器、每个处理器 1 个内核的 VMWare 工作站 VM 中,时间报告大约需要 17 毫秒才能完成。
当我在我的主机上运行它时,(i7-6700)秒表始终报告 0 毫秒完成。有人告诉我,我只是在我的主机上使用 WaitFor “幸运”,通常我应该期望单个线程有 20 毫秒。显然,这意味着试图将线程执行时间降低到 20 毫秒以下是不可能的。
是否有关于启动线程需要多快的明确解释?
我用于测试的代码如下。
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.
解决方案
在 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 中,切片时间在上下文切换时间成本和响应性之间得到了很好的平衡。即使有办法将其降低到 1ms - 0.5ns,如果硬件架构允许,较低的切片时间并不总是更好。
编辑:某些技术,例如英特尔超线程,允许在同一时间片内同一内核上的多个线程上执行,请参阅评论。
推荐阅读
- postgresql-9.5 - 如何对包含由句点分隔符分隔的字母数字字符的文本字段进行排序?
- visual-studio - Vue.JS 应用程序抛出错误 JS 预期
- pandas - 数据框在osx中保存和加载的行大小不同
- c++ - 如何从该输入文件中取出第一列,获取该列的其余部分(逐列)
- node.js - 无论如何将量角器的输出发送到文件中?
- python - 使用pyspark时如何访问hive表中的注释?
- ios - 如何通过按音量增大或减小按钮打开“AVPlayer”中播放视频的音量?
- javascript - 我可以从另一个 nodejs 应用程序监控 nodejs 应用程序吗?
- dll - 我需要帮助在只需要 x86 的应用程序中运行 x64 .dll
- react-native - 为什么 react-native 链接只链接 ios 不能链接 android