相同的代码作为Windows服务运行速度比GUI应用程序慢

时间:2012-12-02 23:45:28

标签: windows performance delphi windows-services delphi-2007

我有一些Delphi 2007代码,它运行在两个不同的应用程序中,一个是GUI应用程序,另一个是Windows服务。奇怪的是,虽然GUI应用程序在技术上似乎有更多的“待办事项”,绘制GUI,计算一些统计数据等,但Windows服务在运行时始终使用更多的CPU。 GUI应用程序使用大约3-4%的CPU功率,服务使用率在6-8%的范围内。

当它们一起运行时,两个应用程序的CPU负载大约翻倍。

除了在Windows窗体应用程序中添加GUI代码外,两个应用程序中的基本代码相同。

这种行为有什么理由吗? Windows服务应用程序是否具有某种固有的开销,或者我是否需要查看代码以找到我的书中出现的意外行为?

编辑:

有时间仔细查看代码,我认为以下建议GUI应用程序花费一些时间等待重新绘制,导致CPU负载下降可能是不正确的。应用程序都是线程化的,这意味着GUI重新绘制不应影响CPU负载。

为了确保我首先尝试从应用程序中删除所有GUI组件,只留下一个空白表单。这并没有增加程序的CPU负载。然后我经历了在用于更新UI的工作线程中删除所有对Synchronize的调用。这有相同的结果:CPU负载没有变化。

服务中的代码如下所示:

procedure TLsOpcServer.ServiceExecute(Sender: TService);
begin
  // Initialize OPC server as NT Service
  dmEngine.AddToLog( sevInfo, 'Service', 'Name', Sender.Name );
  AddLocalServiceKeysToRegistry( Sender.Name );

  dmEngine.AddToLog( sevInfo, 'Service', 'Execute', 'Started' );
  dmEngine.Start( True );
  //
  while not Terminated do
  begin
    ServiceThread.ProcessRequests( True );
  end;

  dmEngine.Stop;
  dmEngine.AddToLog( sevInfo, 'Service', 'Execute', 'Stopped' );
end;

dmEngine.Start将启动并注册OPC服务器并初始化套接字。然后它启动一个线程,它对输入的OPC信号有所帮助。在GUI应用程序的主要表单上的FormCreate中进行了相同的完全调用。

我将研究GUI应用程序如何启动,我没有编写这段代码,因此试图弄清楚它是如何工作的有点冒险:)

EDIT2

这有点有趣。我运行两个应用程序各1分钟,运行AQTime来对它们进行基准测试。这是结果中最有趣的部分:

在服务中:

程序名称: TSignalList :: HandleChild

执行时间: 20.105963821084

Hitcount: 5961231

在GUI应用程序中:

程序名称: TSignalList :: HandleChild

执行时间: 7.62424101324976

命中数: 6383010

编辑3:

我终于回到了能够继续关注这个问题的位置。我发现两个程序在五分钟运行期间都具有大约相同的hitcount,但在服务中执行时间要高得多。对于HandleValue,hitcount为4 300 258,服务执行时间为21.77s,在GUI应用程序中,hitcount为4 254 018,执行时间为9.75秒。

代码如下所示:

function TSignalList.HandleValue(const Signal: string; var Tag: TTag; const CreateIfNotExist: Boolean):        HandleStatus;
var
  Index: integer;
begin
  result := statusNoSignal;
  Tag := nil;

  if not Assigned( Values ) then
  begin
    Values := TValueStrings.Create;
    Values.CaseSensitive  := defDefaultCase;
    Values.Sorted         := True;
    Values.Duplicates     := dupIgnore;
    Index := -1;  // Garantied no items in list
  end else
  begin
    Index := Values.IndexOf( Signal );
  end;

  if Index = -1 then
  begin
    if CreateIfNotExist then
    begin
      // Value signal does not exist create it
      Tag := TTag.Create;
      if Values.AddObject( Signal, Tag ) > -1 then
      begin
        result := statusAdded;
      end;
    end;
  end else
  begin
    Tag := TTag( Values.Objects[ Index ] );
    result := statusExist;
  end;
end;

两个应用程序输入的“CreateIfNotExist”情况完全相同。 TValueStrings是TStringList的直接后代,没有任何重载。

1 个答案:

答案 0 :(得分:6)

您是否计划执行核心功能?如果是这样,你有没有衡量差异?我认为,如果你这样做,除非你将其他功能(如更新GUI)添加到该核心功能的代码中,否则它们之间不会发现太大的区别。

消耗较少的CPU并不意味着它的运行速度较慢。 GUI应用程序可能会在重新绘制时更频繁地等待,这取决于GPU(也可能是系统的其他部分)。因此,GUI应用程序可能会消耗较少的CPU功率,因为​​CPU在继续执行下一条指令之前正在等待系统的其他部分。