Подтвердить что ты не робот

Как я могу улучшить производительность WMI с помощью delphi?

Я написал простую функцию для извлечения системной информации с помощью 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.
4b9b3361

Ответ 1

Вот некоторые советы по улучшению производительности WMI

1.) Повторно вызовите вызов CreateOleObject

2.) Повторное использование соединения WMI

Одной из более дорогих задач является подключение к WMI-сервисам, поэтому повторно подключайте это соединение вместо создания одного соединения каждый раз, когда вы вызываете функцию.

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 мс (на моем ноутбуке).

Ответ 2

Это общее правило.

Когда вы говорите, что хотите получить много дополнительной информации, я предполагаю, что это означает, что вы будете многократно вызывать эту функцию, возможно, в цикле. Для настройки производительности вам просто нужно взять те вещи, которые стоят много времени и что вы можете повторно использовать, из цикла, то есть кэшировать их.

В этом случае объект CreateOleObject, скорее всего, будет стоить вам большую часть времени, в качестве первого прохода, который я бы поставил вне цикла (или нескольких вызовов) и передал ваш sWebLocator в функцию, в качестве второго прохода вы можете как и вызов ConnectServer из функции, а также передать объект sWMIService.