14

WMI を使用してシステム情報を取得する単純な関数を作成し、パラメーターとしてクラスとプロパティ名を渡しました。このような関数を実行すると

  Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
  Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
  Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));

実行時間は約1300ミリ秒です。

多くの追加情報を取得する必要があるため、この関数の実行時間を短縮できますか?

これは、関数を使用したサンプル アプリケーションです。

{$APPTYPE CONSOLE}

uses
  Diagnostics,
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

function  GetWMIInfo(const WMIClass, WMIProperty:string): string;
var
  sWbemLocator  : OLEVariant;
  sWMIService   : OLEVariant;
  sWbemObjectSet: OLEVariant;
  sWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  Result:='';
  sWbemLocator  := CreateOleObject('WbemScripting.SWbemLocator');
  sWMIService   := sWbemLocator.ConnectServer('', 'root\CIMV2', '', '');
  sWbemObjectSet:= sWMIService.ExecQuery('SELECT * FROM '+WMIClass,'WQL');
  oEnum         := IUnknown(sWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, sWbemObject, iValue) = 0 then
    Result:=sWbemObject.Properties_.Item(WMIProperty).Value;
end;

var
 SW : TStopwatch;

begin
 try
    CoInitialize(nil);
    try
      SW.Reset;
      SW.Start;
      Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
      Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
      Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));
      SW.Stop;
      Writeln('Elapsed ms '+FormatFloat('#,0.000',SW.Elapsed.TotalMilliseconds));
    finally
      CoUninitialize;
    end;
 except
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Readln;
end.
4

2 に答える 2

21

これらは、WMI のパフォーマンスを改善するためのヒントです。

1.) への呼び出しを再利用するCreateOleObject

2.) WMI 接続を再利用する

より高価なタスクの 1 つは、WMI サービスへの接続を確立することです。そのため、関数を呼び出すたびに 1 つの接続を作成するのではなく、その接続を再利用します。

3.) 使用する列のみを取得します

WMI を取得するすべてのプロパティには、Windows レジストリ、WinAPI などのさまざまなソースがあり、列を制限するとパフォーマンスが向上します。詳細については、この記事をお読みくださいHow obtain the source of the WMI Data

4.) WQL 文を実行するときにWBEM_FLAG_FORWARD_ONLYフラグを使用します。

上記のヒントに従って、サンプルアプリを書き直しました

{$APPTYPE CONSOLE}

uses
  Diagnostics,
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;

function  GetWMIInfo(const WMIClass, WMIProperty:string): string;
const
  wbemFlagForwardOnly = $00000020;
var
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  Result:='';
  FWbemObjectSet:= FWMIService.ExecQuery(Format('Select %s from %s',[WMIProperty, WMIClass]),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
    Result:=FWbemObject.Properties_.Item(WMIProperty).Value;
end;

var
 SW : TStopwatch;

begin
 try
    CoInitialize(nil);
    try
      SW.Reset;
      SW.Start;
      FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
      Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
      Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
      Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));
      SW.Stop;
      Writeln('Elapsed ms '+FormatFloat('#,0.000',SW.Elapsed.TotalMilliseconds));
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Readln;
end.

そして、実行は1245から180ミリ秒になります(私のラップトップで)。

于 2012-04-17T22:01:35.097 に答える
4

これは一般的な経験則です。

多くの追加情報を取得したいと言った場合、おそらくループでこの関数を何度も呼び出すことになると思います。パフォーマンス チューニングの場合は、多くの時間を要し、再利用できるものをループから取り出す、つまりキャッシュするだけで済みます。

この場合、CreateOleObject に多くの時間が費やされる可能性があります。最初のパスとしてループ (または複数の呼び出し) の外に置き、2 番目のパスとして sWebLocator を関数に渡します。 ConnectServer も関数から呼び出し、sWMIService オブジェクトも渡します。

于 2012-04-17T21:58:41.320 に答える