Enumerating in separate threads--pointless because the thread is blocked? (.NET 2.0)
- From: "Homer J. Simpson" <root@xxxxxxxxx>
- Date: Wed, 6 Feb 2008 16:23:43 -0500
I'm probably not doing things like I'm "supposed' to, because I'm not
getting the results I'm expecting...
Sorry for the long post, but please bear with me...I have to elaborate on
what I'm trying to do what I've done trying to get there.
I'm retrieving all the details for the cimv2\Win32_Product class (others
too, but this is the one class I'm testing against). I'm not using a
'where' clause to narrow down the results--that's besides the point. As
others have probably already observed, this can be quite slow. Upwards of a
minute on my system, probably more. I thought I'd alleviate the problem by
having a thread retrieve data in the background, so my UI remains responsive
and the user has a Cancel button to abort the data retrieval process.
My .NET pseudo-code is as follows:
ManagementObjectSearcher mos = new ManagementObjectSearcher( ...query... );
ManagementObjectCollection moc = mos.Get();
foreach( ManagementBaseObject mbo in moc ) {
ProcessThisRecord( mbo );
}
However, my observation has been that as soon as I single-step (in the
debugger) over mos.Get(), an instance of wmiprvse.exe pins the CPU, and then
as I enter the foreach loop, whatever thread is executing the loop then
blocks, and the debugger waits for wmiprvse.exe to finish fetching all the
data (a minute on my system for this particular class) before it'll return
on the next line of code. Obviously my UI won't even repaint while it's
busy.
I tried doing this in a separate thread. The UI remains responsive, and my
Cancel button's callback is triggered correctly. All it does is set a bool
flag (bCancelPending) that's a member of my form class. The idea was to
have:
foreach( ... )
if( bCancelPending == true )
break;
ProcessThisRecord( mbo );
}
However, the thread is blocked as soon as I enter the foreach loop. After a
minute, execution resumes, the Cancel flag is checked, and it breaks out of
the loop, as desired...however, I still had to wait for all the records to
be fetched before the code checked for the flag...duh. Once I'm past that
initially delay, ripping through the loop takes no time at all.
I thought instead of using a foreach loop, I'd use something like:
lock( moc.SyncRoot ) {
ManagementObjectCollection.ManagementObjectEnumerator e =
moc.GetEnumerator();
while( e.MoveNext() ) {
ManagementBaseObject mbo = e.Current;
ProcessThisRecord( mbo );
}
}
Much to my surprise, even with this, as I single-step through the code,
e.MoveNext() also blocks while all the data is fetched...after the
one-minute pause, the loop then resumes and again manages to rips through
the data in no time at all...so once again, there's no point in trying to
set a flag to verify within the loop.
In other words, unless I'm doing something very wrong, there's no point in
even trying to spawn different threads to do work in the background.
Then I stumbled upon ManagementOperationObserver--neat...it definitely seems
like the preferred way to get data from WMI asynchronously, without the
hassle of setting up my own threading.
I hooked it all up, managed to get the callbacks triggered...only, this is
even slower than looping. Other classes, like Win32_Processor, which only
returns 2 records on my dual-core system, and is nearly instantaneous using
a loop, takes 45-60 seconds using this callback technique. I'm not sure,
based on my Google search results, whether further investigation in that
area is warranted, because it seems like there's a lot of complaints that
this callback technique is slow. If it's *expected* to be as slow as I'm
seeing, then there's no point in me spending more time here.
Now...I suspect I'm gonna have to post some actual code before I can get
concrete answers...fact is, I've made such a mess of my code right now after
so much trial and error that I've just had to revert back to my original
version, which makes no attempt at threading or asynchronous operations.
What I'm really looking for is a simple, *working* sample that
asynchronously fetches data from a class, fills some control (listview or
anything else) with this data, and lets the user click a Cancel button to
abort fetches that take a long time (and preferably then fills some control
with the data that has been retrieved up to this point). Bonus points for
something that can later resume where it left off, but I'll be a happy
camper if I can get this far.
.
- Follow-Ups:
- Re: Enumerating in separate threads--pointless because the thread is blocked? (.NET 2.0)
- From: Homer J. Simpson
- Re: Enumerating in separate threads--pointless because the thread is blocked? (.NET 2.0)
- Prev by Date: Win32_Group.Name= / Win32_Account.Name not working with Authentication
- Next by Date: Disk I/O by process and file
- Previous by thread: Win32_Group.Name= / Win32_Account.Name not working with Authentication
- Next by thread: Re: Enumerating in separate threads--pointless because the thread is blocked? (.NET 2.0)
- Index(es):
Relevant Pages
|