2012-04-17 21 views
13

Tôi đã viết một hàm đơn giản để truy xuất thông tin hệ thống bằng cách sử dụng WMI, truyền tham số lớp và tên thuộc tính. khi tôi thực hiện chức năng như thế nàyLàm cách nào để cải thiện hiệu năng WMI bằng delphi?

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

Thời gian thực hiện là khoảng 1300 ms.

Tôi cần truy xuất nhiều thông tin bổ sung, Vì vậy, có thể giảm thời gian thực hiện chức năng này không?

Đây là một ứng dụng mẫu với chức năng

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

Trả lời

19

Đây là một số lời khuyên để cải thiện hiệu suất WMI

1.) Reutilize cuộc gọi đến CreateOleObject

2.) Tái sử dụng Connection WMI

Một trong những nhiệm vụ tốn kém hơn là tạo ra một kết nối đến các dịch vụ WMI, do đó, tái sử dụng conneciton đó thay vì tạo ra một conneciton mỗi lần gọi hàm.

3.) Chỉ truy xuất các cột mà bạn muốn sử dụng

Mỗi tài sản mà lấy WMI có nhiều nguồn khác nhau như Windows registry, các WinAPI và như vậy, việc hạn chế các cột sẽ cải thiện hiệu suất. đọc bài viết này để biết thêm thông tin How obtain the source of the WMI Data

4.) Sử dụng cờ WBEM_FLAG_FORWARD_ONLY khi bạn thực thi câu WQL.

Tiếp theo những lời khuyên trên, chúng tôi viết lại ứng dụng mẫu của bạn

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

Còn việc xử tử đi 1245-180 ms (trên máy tính xách tay của tôi).

+6

+1. Đẹp, và một lần nữa bạn làm cho tôi xóa câu trả lời kém cỏi của tôi. :) Ngoài những gì bạn nói, các poster có thể muốn nhìn vào MagWMI, một bộ miễn phí của Delphi wrappers mà làm cho mọi thứ dễ dàng hơn. Nó trong nội bộ hiện một số bộ nhớ đệm của thông tin mà làm cho nhiều truy vấn dễ dàng hơn nhiều. Trình bao bọc là miễn phí và đi kèm với một ứng dụng demo thực sự mở rộng có thể giúp ích. –

+2

vâng, điều này khá giống với những gì tôi nói ... tuy nhiên cá nhân tôi nghĩ rằng một mô hình chung tốt hơn là chuyển các vars dịch vụ đã lưu trữ vào hàm, điều này cho phép DI và chế nhạo những vars đó trong một khuôn khổ thử nghiệm . –

+0

Tắt khóa học tốt hơn là tạo một đối tượng để đóng gói kết nối và chức năng. ứng dụng mẫu này chỉ là bằng chứng về khái niệm. Ngoài ra điểm 3 không bao giờ được đề cập và là rất quan trọng. – RRUZ

4

Đây là một quy luật chung của ngón tay cái.

Khi bạn nói bạn muốn truy xuất nhiều thông tin bổ sung, tôi cho rằng điều đó có nghĩa là bạn sẽ gọi hàm này rất nhiều, có thể trong vòng lặp. Để điều chỉnh hiệu suất, bạn chỉ cần thực hiện những điều đó tốn rất nhiều thời gian và bạn có thể sử dụng lại, trong vòng lặp, tức là lưu chúng vào bộ nhớ cache.

Trong trường hợp này, CreateOleObject có khả năng sẽ khiến bạn mất nhiều thời gian, vì lần đầu tiên, tôi sẽ đặt bên ngoài vòng lặp (hoặc nhiều cuộc gọi) và chuyển sWebLocator của bạn vào hàm. có thể muốn thực hiện cuộc gọi ConnectServer cũng như chuyển đối tượng sWMIService.

Các vấn đề liên quan