Comment puis-je améliorer les performances WMI en utilisant delphi?

j'ai écrit une fonction simple pour récupérer des informations système en utilisant le WMI, en passant comme paramètre la classe et le nom de la propriété. lorsque j'exécute la fonction comme ceci

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

Le temps d'exécution est d'environ 1300 ms.

j'ai besoin de récupérer un grand nombre d'informations supplémentaires, Est Donc possible de réduire le temps d'exécution de cette fonction?

C'est un exemple d'application avec la fonction

{$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('', 'rootCIMV2', '', '');
  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.
13
demandé sur Salvador 2012-04-18 01:34:43

2 réponses

voici quelques conseils pour améliorer la performance de WMI

1.) Réutiliser l'appel à CreateOleObject

2.) Réutiliser la connexion WMI

une des tâches les plus coûteuses est de faire une connexion aux services WMI, réutilisez donc ce conneciton au lieu de créer un conneciton à chaque fois qui appellent la fonction.

3.) Récupérez seulement les colonnes que vous voulez utiliser

chaque propriété qui récupère le WMI a différent des sources comme le registre Windows, Le WinAPi et ainsi de suite, la restriction des colonnes améliorera la performance. lisez cet article pour plus d'info How obtain the source of the WMI Data

4.) WBEM_FLAG_FORWARD_ONLY marquez lorsque vous exécutez la phrase WQL.

suivant les conseils ci-dessus, j'ai réécrit votre application d'échantillonnage

{$APPTYPE CONSOLE}

uses
  Diagnostics,
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;

function  GetWMIInfo(const WMIClass, WMIProperty:string): string;
const
  wbemFlagForwardOnly = 000020;
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.

et l'exécution va de 1245 à 180 ms (sur mon ordinateur portable).

19
répondu RRUZ 2012-04-17 22:06:36

C'est une règle générale.

quand vous dites que vous voulez récupérer beaucoup d'informations supplémentaires, je suppose que cela signifie que vous appellerez cette fonction beaucoup, peut-être dans une boucle. Pour le réglage des performances, vous avez simplement besoin de prendre ces choses qui coûtent beaucoup de temps et que vous pouvez réutiliser, hors de la boucle, c'est-à-dire les mettre en cache.

dans ce cas, le CreateOleObject est susceptible de vous coûter la majeure partie du temps, en premier passage je mettrais cela en dehors de la boucle (ou appels multiples) et passer votre sWebLocator dans la fonction, comme un second passage vous pourriez vouloir prendre l'appel ConnectServer hors de la fonction aussi bien et passer l'objet sWMIService dedans aussi bien.

4
répondu Tim Jarvis 2012-04-17 21:58:41