Multithreading 在Delphi中,在后台线程中运行的代码能比在主VCL线程中运行的代码快吗?

Multithreading 在Delphi中,在后台线程中运行的代码能比在主VCL线程中运行的代码快吗?,multithreading,performance,delphi,vcl,timing,Multithreading,Performance,Delphi,Vcl,Timing,如果有人在主VCL线程和后台线程上运行过很多计时代码的经验,我想听听他们的意见。我有一些代码在主线程上的Delphi6应用程序中执行一些繁重的字符串处理。每次我运行一个操作,每个操作的时间在i5四核上的一个线程上徘徊在50毫秒左右。真正让我怀疑的是,在我拥有的旧奔腾4上运行的代码显示了相同的操作时间,而在奔腾4上运行的代码通常比四核慢4倍。我开始怀疑代码所花费的时间是否会比50毫秒少得多,但是主VCL线程(可能是Windows消息处理或执行Windows API调用)的某些方面为操作创建了一个人

如果有人在主VCL线程和后台线程上运行过很多计时代码的经验,我想听听他们的意见。我有一些代码在主线程上的Delphi6应用程序中执行一些繁重的字符串处理。每次我运行一个操作,每个操作的时间在i5四核上的一个线程上徘徊在50毫秒左右。真正让我怀疑的是,在我拥有的旧奔腾4上运行的代码显示了相同的操作时间,而在奔腾4上运行的代码通常比四核慢4倍。我开始怀疑代码所花费的时间是否会比50毫秒少得多,但是主VCL线程(可能是Windows消息处理或执行Windows API调用)的某些方面为操作创建了一个人工“地板”。注意,如果有必要的话,操作是由套接字上的传入请求触发的,但是在完全接收数据之前不会进行时间测量

在我开始将所有代码转移到后台线程进行测试之前,我想知道是否有人对这方面有任何常识?您对在主VCL线程上和主VCL线程下运行代码有何经验?注意,在测试期间绝对没有用户触发的活动进行时,进行计时测量

我还想知道,将线程的优先级提高到略低于实时级别是否会有好处。在使用这些标志进行实验时,我从来没有看到运行时间有多大的改进


--roschler

当您的代码控制VCL线程时,例如,如果它在一个方法中,并且没有调用任何VCL控件或调用Application.ProcessMessages,则运行时不会因为它在主VCL线程中而受到影响

没有开销,因为当您在自己的代码中时,您“拥有”线程的全部处理能力


我建议您使用分析工具来找出实际的瓶颈所在。

鉴于所有线程都具有相同的优先级,正如它们通常所具有的优先级一样,因此不会有什么不同,原因如下。如果发现差异,请重新评估代码(确保在VCL和后台线程中运行相同的代码),并确保正确计时:

  • 编译器生成完全相同的代码,它不关心代码是在主线程还是在后台线程中运行。事实上,您可以将整个代码放在一个过程中,并从工作线程的
    Execute()
    和主VCL线程调用该过程

  • 对于CPU,所有内核和线程都是相等的。除非它实际上是一个超线程CPU,并不是所有的内核都是真实的,但看看下一个项目

  • 即使不是所有的CPU内核都相等,线程也不太可能在同一个内核上运行,操作系统可以随意移动它(并且确实安排线程在不同的时间在不同的内核上运行)

  • 消息传递开销对于主VCL线程来说并不重要,因为除非您手动调用
    Application.ProcessMessages()
    ,否则当您的过程工作时,消息泵将停止。消息泵是被动的,您的线程需要从队列中请求消息,但是由于线程正忙于您的工作,因此它不请求任何消息,因此没有开销


只有一个地方线程不相等,这可能会改变执行速度:是操作系统将线程调度到执行单元(核心),而对于操作系统,线程具有不同的优先级。您可以使用API(由
TThread.Priority
属性使用)告诉操作系统需要对某个线程进行不同的处理。

您是否询问后台线程是否会更快?如果您的后台线程将运行与主线程相同的代码,并且主线程中没有任何其他操作,那么您就不能通过后台线程获得任何东西。线程应用于分割和分配处理负载,否则在主线程中运行时,这些负载将相互竞争和/或相互阻塞。由于您似乎正在处理一个主线程在其他方面处于空闲状态的情况,因此简单地生成一个线程来运行缓慢的代码是没有帮助的

线程并不是神奇的,它们不能加速慢代码或消除与主线程上的争用无关的特定段中的处理瓶颈。确保你的代码没有做你不知道的事情,并且你的计时方法是正确的


我的第一个预感是,你与套接字的交互正在以一种你没有察觉到的方式影响你的计时。。。(我知道你说你确定这没有关系,但也许再检查一下…

如果没有简单的源代码来重现问题,以及如何对线程进行计时,就很难理解软件中发生了什么

听起来很像:

  • 架构问题-如何定义线程
  • 一个度量问题——你如何给线程计时
  • 内存管理器和RTL字符串相关实现的组合
关于最新一点,请考虑:

  • 当前的内存管理器(FastMM4)在多核CPU上的伸缩性不好;尝试使用每线程内存管理器,例如-注意,免费Pascal编译器团队最近从头开始编写了一个新的scaling MM,以避免此类问题
  • 尝试更改字符串进程实现,以避免内存分配(使用静态缓冲区)和字符串引用计数(每个字符串引用计数访问都会产生一个
    LOCK DEC/INC
    ,在多代码上无法很好地扩展)
       procedure TMyThread.Execute;
       begin
           while not Terminated do 
             Synchronize(DoWork);
       end;