3

2 つの異なるアプリケーションで実行される Delphi 2007 コードがいくつかあります。1 つは GUI アプリケーションで、もう 1 つは Windows サービスです。奇妙な点は、GUI アプリケーションには、GUI の描画、統計の計算など、技術的にはより多くの「やるべきこと」があるように見える一方で、Windows サービスは、実行時に一貫してより多くの CPU を使用していることです。GUI アプリケーションが約 3 ~ 4% の CPU 電力を使用する場合、サービスは 6 ~ 8% の範囲で使用されます。

それらを一緒に実行すると、両方のアプリケーションの CPU 負荷は約 2 倍になります。

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

ヒットカウント: 5961231

GUI アプリケーションで:

プロシージャ名: TSignalList::HandleChild

実行時間: 7.62424101324976

ヒット数: 6383010

編集3:

私はようやく、この問題を見続けられる立場に戻ってきました。5 分間の実行でヒット数がほぼ同じである 2 つのプロシージャを見つけましたが、サービスでは実行時間がはるかに長くなります。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 の直接の子孫です。

4

1 に答える 1

7

コア機能の実行時間を計りましたか? もしそうなら、あなたは違いを測定しましたか?そうした場合、GUI の更新などの他の機能をそのコア機能のコードに追加しない限り、それらの間に大きな違いは見られないと思います。

CPU の消費が少ないからといって、実行速度が遅くなるわけではありません。GUI アプリは、GPU (およびシステムの他の部分) にも依存する再描画をより頻繁に待機する可能性があります。したがって、CPU は次の命令を続行する前にシステムの他の部分を待機しているため、GUI アプリが消費する CPU 電力が少なくなる可能性があります。

于 2012-12-03T02:01:12.347 に答える