同时运行它们时,两个应用程序的CPU负载大致翻倍。
这两个应用程序的基本代码相同,除了在Windows窗体应用程序中添加了GUI代码之外。
这种行为有什么原因吗?Windows服务应用程序有某种固有的开销,还是我需要查找代码中这种出乎意料的行为的根源?
编辑:
经过仔细查看代码后,我认为下面的建议,即GUI应用程序花费一些时间等待重新绘制,导致CPU负载下降,可能是不正确的。这两个应用程序都是线程化的,这意味着GUI重绘不应该影响CPU负载。
为了确保,我先尝试从应用程序中删除所有GUI组件,只留下一个空白表单。那并没有增加程序的CPU负载。然后,我逐步删除了所有工作线程中用于更新UI的同步调用。这也有相同的结果: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应用程序如何启动,因为我没有编写这段代码,所以尝试弄清楚它的工作原理是一次冒险 :)
编辑2
这有点有趣。我分别运行了两个应用程序一分钟,并使用AQTime对它们进行了基准测试。结果中最有趣的部分如下:
在服务中:
过程名称: TSignalList::HandleChild
执行时间: 20.105963821084
命中次数: 5961231
在GUI应用程序中:
过程名称: TSignalList::HandleChild
执行时间: 7.62424101324976
命中次数: 6383010
编辑3:
我终于回到了可以继续研究这个问题的位置。我找到了两个过程,在五分钟的运行中它们的命中次数大致相同,但在服务中执行时间要长得多。对于HandleValue,服务中的命中次数为4,300,258,执行时间为21.77秒,在GUI应用程序中的命中次数为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的直接后代,没有任何重载。