Reputation: 9116
I have a method that returns list of services on remote machine. I'm getting the ManagementObjectCollection using ManagementObjectSearcher.Get() and WIN32 query. Then in foreach loop I'm creating instance of my Service class and add it to result List. While initializing new Service I'm getting ManagementObject properties using GetPropertyValue(string). The problem i'm facing is that this process is very slow. I think that GetPropertyValue is slow(I'm using it 7 times per loop). Is there faster way of getting properties from ManagementObject class?
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);}
Upvotes: 1
Views: 5370
Reputation: 760
I have been fighting with this, trying to understand what is so slow.
I wrote a test program, and used Stopwatch to time practically everything.
I have a wql
query that returns 3 devices from Win32_PnPSignedDriver
.
I used three different methods to retrieve the results from the query.
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();
searcher.Get()
is plenty fast.
I tested three methods of retrieving data from ManagementObjectCollection queryResults.
foreach (ManagementBaseObject device in queryResults) { }
IEnumerator enumerator = queryResults.GetEnumerator(); while (enumerator.MoveNext()) { }
queryResults.CopyTo(deviceArray, 0); foreach (var btDevice in deviceArray)
First round testing:
Method 1: Was very slow -- over 3000 ms to execute an empty loop.
Method 2: Was very fast. 1 ms
Method 3: Also very fast. 0 ms.
Then I saw the fault in my testing. The first loop counted the object in the collection, and then this was remembered by the framework. If I executed Method 1 several times, only the initial loop was slow, but then repeating the foreach
was 0 to 1 ms.
I restructured my test to re-execute the query before each fetch of the data.
Method 1: Was slow every time.
Method 2: Also slow every time.
Method 3: My Stopwatch timing reported 0 to 1 ms, but I noticed the execution time was much longer. ???
Looking deeply into what I coded, I saw that I did not time the following line:
ManagementObject[] deviceArray = new ManagementObject[queryResults.Count];
Which is actually two commands:
var count = queryResults.Count;
ManagementObject[] deviceArray = new ManagementObject[count];
I timed each separately, and saw that the queryResults.Count
took almost all the time. Often > 3000 ms.
I then hard-coded the size of the array to avoid the call: queryResults.Count
However, when I executed
queryResults.CopyTo(deviceArray, 0);
The CopyTo
method still needed to know how many items are in the ManagementObjectCollection
, and now the CopyTo
took > 3000 ms where it had been 0 or 1 ms before.
So, it would appear that ManagementObjectCollection
. get_Count
is the bottleneck, and I do not know anyway to retrieve the results without causing the Count getter to be executed.
Upvotes: 8