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)
我一直在与这个斗争,试图理解什么是如此缓慢。
我编写了一个测试程序,并使用秒表对几乎所有内容进行计时。我有一个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 检索数据的三种方法。
foreach (ManagementBaseObject device in queryResults) { }IEnumerator enumerator = queryResults.GetEnumerator(); while (enumerator.MoveNext()) { }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 的情况下检索结果。