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.
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).
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.