2012-04-17 12 views
13

Ich schrieb eine einfache Funktion zum Abrufen von Systeminformationen mit dem WMI, übergibt als Parameter die Klasse und den Namen der Eigenschaft. Wenn ich die Funktion wie folgt ausfühleWie kann ich die WMI-Leistung mithilfe von Delphi verbessern?

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

Die Ausführungszeit beträgt etwa 1300 ms.

Ich brauche viele zusätzliche Informationen abrufen, So ist möglich, die Zeit der Ausführung dieser Funktion zu reduzieren?

Dies ist eine Beispielanwendung, mit der Funktion

{$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. 

Antwort

19

Dies sind einige Tipps, um die WMI-Leistung

1.) wiederzuverwenden, den Anruf zu CreateOleObject

2.) Reuse die WMI-Verbindung

Eine teureren Aufgabe zu verbessern, ist eine Verbindung herzustellen zu die WMI-Dienste, verwenden Sie diese Verbindung erneut, anstatt jeweils eine Verbindung zu erstellen, die die Funktion aufruft.

3.) Nur die Spalten abrufen, die Sie

Jede Eigenschaft verwenden möchten, die abgerufen werden die WMI verschiedenen Quellen wie der Windows-Registrierung hat, die winapi und so weiter, werden die Spalten zu beschränken, die Leistung verbessern. Lesen Sie diesen Artikel für weitere Informationen How obtain the source of the WMI Data

4.) Verwenden Sie die WBEM_FLAG_FORWARD_ONLY Flag, wenn Sie den WQL-Satz ausführen.

die oben genannten Tipps Nach umschrieb ich Ihre Beispielanwendung

{$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. 

und die Ausführung geht 1245-180 ms (auf meinem Laptop).

+6

+1. Nett, und wieder lässt du mich meine minderwertige Antwort löschen. :) Zusätzlich zu dem, was Sie gesagt haben, könnte das Poster MagWMI betrachten, eine kostenlose Sammlung von Delphi-Wrappern, die die Arbeit erleichtern. Es führt intern ein Caching von Informationen durch, die mehrere Abfragen viel einfacher machen. Der Wrapper ist kostenlos und kommt mit einer wirklich umfangreichen Demo-App, die helfen könnte. –

+2

yep, das ist ziemlich genau die gleiche Sache, die ich sagte ... aber persönlich denke ich, ein besseres allgemeines Muster besteht darin, die zwischengespeicherten Service-Vars an die Funktion zu übergeben, dies ermöglicht DI und Spott dieser Vars in einem Test-Framework . –

+0

Natürlich ist es besser, ein Objekt zu erstellen, um die Verbindung und die Funktion zu kapseln. Diese Beispiel-App ist nur ein Proof of Concept. Auch der Punkt 3 wird nie erwähnt und ist sehr wichtig. – RRUZ

4

Dies ist eine Faustregel.

Wenn Sie sagen, dass Sie viele zusätzliche Informationen abrufen möchten, nehme ich an, dass Sie diese Funktion sehr oft aufrufen, möglicherweise in einer Schleife. Für die Leistungsoptimierung müssen Sie einfach die Dinge nehmen, die viel Zeit kosten und die Sie wiederverwenden, aus der Schleife herausnehmen, d. H. Zwischenspeichern können.

In diesem Fall kostet das CreateOleObject wahrscheinlich den Großteil der Zeit, als ersten Durchlauf würde ich das außerhalb der Schleife (oder mehrere Aufrufe) setzen und Ihren sWebLocator in die Funktion übergeben, als einen zweiten Durchlauf möchte möglicherweise auch den ConnectServer-Aufruf aus der Funktion entfernen und das Objekt sWMIService ebenfalls übergeben.

Verwandte Themen