我编写了一个简单的函数来使用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.
答案 0 :(得分:20)
这些是提高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毫秒(在我的笔记本电脑上)。
答案 1 :(得分:4)
这是一般的经验法则。
当你说你想要检索很多其他信息时,我认为这意味着你将在很多时候调用这个函数,可能是在一个循环中。对于性能调优,您只需要花费大量时间并且可以在循环之外重用它们,即缓存它们。
在这种情况下,CreateOleObject很可能在很大程度上耗费你的时间,作为第一遍我将它放在循环外(或多次调用)并将你的sWebLocator传递给函数,作为第二次传递你可能喜欢从函数中取出ConnectServer调用并同时传递sWMIService对象。