Delphi 2010:无线程与线程

发布于 2024-09-18 05:54:56 字数 1931 浏览 6 评论 0原文

我是delphi 2010的用户,我当前的机器是intel core i7,运行windows 7 x64。我编写了以下代码:

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    FCount: Integer;
    FTickCount: Cardinal;
    procedure DoTest;
    procedure OnTerminate(Sender: TObject);
  end;

  TMyThread = class(TThread)
  private
    FMethod: TProc;
  protected
    procedure Execute; override;
  public
    constructor Create(const aCreateSuspended: Boolean; const aMethod: TProc);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
    T1, T2: Cardinal;
begin
  T1 := GetTickCount;
  for i := 0 to 9 do
    DoTest;
  T2 := GetTickCount;
  Memo1.Lines.Add(Format('no thread=%4f', [(T2 - T1)/1000]));
end;

procedure TForm1.Button2Click(Sender: TObject);
var T: TMyThread;
    i: integer;
begin
  FCount := 0;
  FTickCount := GetTickCount;

  for i := 0 to 9 do begin
    T := TMyThread.Create(True, DoTest);
    T.OnTerminate := OnTerminate;
    T.Priority := tpTimeCritical;

    if SetThreadAffinityMask(T.Handle, 1 shl (i mod 8)) = 0 then
      raise Exception.Create(IntToStr(GetLastError));

    Inc(FCount);
    T.Start;
  end;
end;

procedure TForm1.DoTest;
var i: integer;
begin
  for i := 1 to 10000000 do
    IntToStr(i);
end;

procedure TForm1.OnTerminate(Sender: TObject);
begin
  Dec(FCount);
  if FCount = 0 then
    Memo1.Lines.Add(Format('thread=%4f', [(GetTickCount - FTickCount)/1000]));
end;

constructor TMyThread.Create(const aCreateSuspended: Boolean; const aMethod:
    TProc);
begin
  inherited Create(aCreateSuspended);
  FMethod := aMethod;
  FreeOnTerminate := True;
end;

procedure TMyThread.Execute;
begin
  FMethod;
end;

单击Button1将显示12.25秒,而Button2将显示12.14秒。我的问题是,尽管我正在运行并行线程,但为什么我无法获得更明显的时间差异(少于 10 秒)?

I'm user of delphi 2010, my current machine is intel core i7, running windows 7 x64. I've write the following codes:

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    FCount: Integer;
    FTickCount: Cardinal;
    procedure DoTest;
    procedure OnTerminate(Sender: TObject);
  end;

  TMyThread = class(TThread)
  private
    FMethod: TProc;
  protected
    procedure Execute; override;
  public
    constructor Create(const aCreateSuspended: Boolean; const aMethod: TProc);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
    T1, T2: Cardinal;
begin
  T1 := GetTickCount;
  for i := 0 to 9 do
    DoTest;
  T2 := GetTickCount;
  Memo1.Lines.Add(Format('no thread=%4f', [(T2 - T1)/1000]));
end;

procedure TForm1.Button2Click(Sender: TObject);
var T: TMyThread;
    i: integer;
begin
  FCount := 0;
  FTickCount := GetTickCount;

  for i := 0 to 9 do begin
    T := TMyThread.Create(True, DoTest);
    T.OnTerminate := OnTerminate;
    T.Priority := tpTimeCritical;

    if SetThreadAffinityMask(T.Handle, 1 shl (i mod 8)) = 0 then
      raise Exception.Create(IntToStr(GetLastError));

    Inc(FCount);
    T.Start;
  end;
end;

procedure TForm1.DoTest;
var i: integer;
begin
  for i := 1 to 10000000 do
    IntToStr(i);
end;

procedure TForm1.OnTerminate(Sender: TObject);
begin
  Dec(FCount);
  if FCount = 0 then
    Memo1.Lines.Add(Format('thread=%4f', [(GetTickCount - FTickCount)/1000]));
end;

constructor TMyThread.Create(const aCreateSuspended: Boolean; const aMethod:
    TProc);
begin
  inherited Create(aCreateSuspended);
  FMethod := aMethod;
  FreeOnTerminate := True;
end;

procedure TMyThread.Execute;
begin
  FMethod;
end;

Click on Button1 will shows 12.25 seconds, while Button2 will shows 12.14 seconds. My problem is why i cannot get more obvious difference of time taken (less than 10 seconds) although i'm running parallel threads ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

双马尾 2024-09-25 05:54:56

内存分配似乎是这里的主要问题。

如果您用代码替换有效负载,

procedure TForm6.DoTest;
var i: integer;
  a: double;
begin
  a := 0;
  for i := 1 to 10000000 do
    a := Cos(a);
end;

则可以很好地并行化,这表明您的框架没有真正的问题。

然而,如果您用内存分配/解除分配替换有效负载,

procedure TForm6.DoTest;
var i: integer;
  p: pointer;
begin
  for i := 1 to 10000000 do begin
    GetMem(p, 10);
    FreeMem(p);
  end;
end;

并行版本的运行速度将比单线程版本慢得多。

调用 IntToStr 时,会分配并销毁临时字符串,这种分配/释放会造成瓶颈。

BTW1:除非您真的知道自己在做什么,否则我强烈建议不要以 tpTimeCritical 优先级运行线程。即使你真的知道自己在做什么,你也不应该这样做。

BTW2:除非你真的知道你在做什么,否则你不应该在线程级别上搞乱亲和力掩码。系统足够智能,可以很好地调度线程。

Memory allocation seems to be the main problem here.

If you replace the payload with

procedure TForm6.DoTest;
var i: integer;
  a: double;
begin
  a := 0;
  for i := 1 to 10000000 do
    a := Cos(a);
end;

the code will parallelize nicely indicating that there's no real problem with your framework.

If you, however, replace the payload with memory allocation/deallocation

procedure TForm6.DoTest;
var i: integer;
  p: pointer;
begin
  for i := 1 to 10000000 do begin
    GetMem(p, 10);
    FreeMem(p);
  end;
end;

the parallel version will run much slower than the single-threaded one.

When calling IntToStr, a temporary string is allocated and destroyed and this allocations/deallocations are creating the bottleneck.

BTW1: Unless you really really know what you're doing, I'm strongly advising against running threads at tpTimeCritical priority. Even if you really really know what you're doing you shouldn't be doing that.

BTW2: Unless you really really know what you're doing, you should not mess with affinity masks on thread level. System is smart enough to schedule threads nicely.

寻找我们的幸福 2024-09-25 05:54:56

如果您有内存密集型线程(许多内存分配/解除分配),您最好使用 TopMM 而不是 FastMM:http://www.TopMM. topsoftwaresite.nl/

FastMM 使用阻止所有其他线程的锁,而 TopMM 则不然,因此它在多核/CPU 上的扩展性更好!

If you have memory intensive threads (many memory allocations/deallocations) you better use TopMM instead of FastMM: http://www.topsoftwaresite.nl/

FastMM uses a lock which blocks all other threads, TopMM does not so it scales much better on multi cores/cpus!

戈亓 2024-09-25 05:54:56

我不是 100% 确定,但 OnTerminate 事件有可能是从 TThread 的上下文中调用的。如果是这种情况(我必须承认我没有检查过这一点),您最好在 FCount 上使用 InterlockedDecrement 并同步 GUI 更新。这只是一个小问题,但在生产代码中这些事情很重要。

I'm not 100% sure, but there's a chance that the OnTerminate event is called from the context of the TThread. If that's the case (I must admit I haven't checked this), you'd be better off using InterlockedDecrement on FCount, and synchronizing the GUI updates. Just a minor point, but in production code these things matter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文