获取 ManagementObject 属性的最快方法

Jac*_*law 1 c# optimization winapi wmi-query

我有一个方法可以返回远程机器上的服务列表。我正在使用 ManagementObjectSearcher.Get() 和 WIN32 查询获取 ManagementObjectCollection。然后在 foreach 循环中,我创建了 Service 类的实例并将其添加到结果列表中。在初始化新服务时,我使用 GetPropertyValue(string) 获取 ManagementObject 属性。我面临的问题是这个过程非常缓慢。我认为 GetPropertyValue 很慢(我每个循环使用它 7 次)。有没有更快的方法从 ManagementObject 类中获取属性?

 var query = new ObjectQuery("Select Name, DisplayName, ProcessId, Description, State, StartMode, StartName From Win32_Service");
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
                ManagementObjectCollection allServices = searcher.Get();
                foreach (ManagementObject p in allServices)
                {Service newService = new Service{ Name = p.GetPropertyValue("Name"),etc...} result.Add(newService);}
Run Code Online (Sandbox Code Playgroud)

Joe*_*e B 5

我一直在与这个斗争,试图理解什么是如此缓慢。

我编写了一个测试程序,并使用秒表对几乎所有内容进行计时。我有一个wql查询,它从Win32_PnPSignedDriver. 我使用了三种不同的方法从查询中检索结果。

ManagementObjectCollection queryResults;
ManagementObjectSearcher searcher = new ManagementObjectSearcher();
var myWql = "SELECT * FROM Win32_PnPSignedDriver WHERE ..."
searcher.Scope = new ManagementScope(@"root\CIMV2");
searcher.Query = new WqlObjectQuery(wmiQry);
queryResults = searcher.Get(); 
Run Code Online (Sandbox Code Playgroud)

searcher.Get() 速度很快。

我测试了从 ManagementObjectCollection queryResults 检索数据的三种方法。

  1. foreach (ManagementBaseObject device in queryResults) { }
  2. IEnumerator enumerator = queryResults.GetEnumerator(); while (enumerator.MoveNext()) { }
  3. queryResults.CopyTo(deviceArray, 0); foreach (var btDevice in deviceArray)

第一轮测试:
方法 1: 非常慢——执行一个空循环超过 3000 毫秒。
方法2: 非常快。1 ms
方法 3: 也非常快。0 毫秒。

然后我在测试中看到了错误。第一个循环计算集合中的对象,然后这个被框架记住。如果我多次执行方法 1,只有初始循环很慢,但随后重复执行foreach0 到 1 毫秒。

我重组了我的测试,以便在每次获取数据之前重新执行查询。
方法一:每次都很慢。
方法二:每次也慢。
方法 3:我的秒表计时报告 0 到 1 毫秒,但我注意到执行时间要长得多。???

深入研究我编码的内容,我发现我没有对以下行进行计时:

ManagementObject[] deviceArray = new ManagementObject[queryResults.Count];
Run Code Online (Sandbox Code Playgroud)

这实际上是两个命令:

var count = queryResults.Count;
ManagementObject[] deviceArray = new ManagementObject[count];
Run Code Online (Sandbox Code Playgroud)

我分别为每个计时,看到queryResults.Count几乎所有的时间。通常 > 3000 毫秒。

然后我硬编码数组的大小以避免调用: queryResults.Count

但是,当我执行

queryResults.CopyTo(deviceArray, 0);  
Run Code Online (Sandbox Code Playgroud)

CopyTo方法仍然需要知道 中有多少项ManagementObjectCollection,现在CopyTo花费了 > 3000 毫秒,而之前是 0 或 1 毫秒。

所以,看起来ManagementObjectCollection. get_Count是瓶颈,我不知道无论如何要在不导致执行 Count getter 的情况下检索结果。

  • 是的,我也没有找到任何解决此问题的方法。+1 分享您的想法。我不知道为什么有人为此给了你 -1 :( (2认同)