Nice to hear from you! Regarding Outlook, I agree that spawning 50 threads is way over the top. There's a difference, though, between consuming 50 threads for the life of the application and starting two threads that will run for a second.
I wonder what Outlook is doing to consume that many threads. I never would have imagined that checking one's e-mail was that complicated!
Regarding the difference between this and PFX, they are solving different problems. PFX is about providing simple means of parallel execution; Jeff's library is about maximizing thread efficiency by avoiding thread blocking altogether by following the
APM model. APM is a requirement when writing programs that: (1) have potentially hundreds or thousands of parallel execution paths (2) spend most of their time blocking Without (1), you won't gain enough through the APM to justify the extra programming effort. Without (2), you won't save anything with the APM. The quintessential application is a sockets server that accepts requests over the net. Because the Internet is slow,
requests may take many seconds from end to end, and yet spend most of their time blocked waiting on a slow network. A well-written asynchronous TCP server can handle a thousand concurrent requests while consuming just a few threads.
APM relies on methods returning with a callback rather than blocking the underlying thread. There are actually fairly few truely asycnhronous methods in the .NET Framework - most are related to networking, where the most gains are to be had.
Jeff's idea is very clever - but it's dubious using it for retrieving web pages in the background in a Win Forms application. The only thing he's achieving is saving the overhead of tying up one or two threads for a few seconds. There was a time when tying
up 1MB of memory for a few seconds was a big deal, but those days are long gone. Using PFX (or asynchronous delegates, which interestingly don't follow the APM) would be simpler and just as effective.
By far, the most common use for the async-callback-method model is writing a TCP or HTTP server capable of handling hundreds of concurrent requests. It's NOT required within ASP.NET apps because the ASP.NET infrastructure already does this for you. It's
also not needed around making database calls within a web app because the DB server will nearly always be more of a bottleneck than the accompanying thread overhead. And who in real life would give up the productivity of the high-level synchronous DB libraries
such as LINQ to SQL and revert to using low-level async-compliant SqlCommand objects and the like?
So if you were writing a large TCP or HTTP server from scratch yourself, Jeff's library may be very helpful. The only problem I can see (unless I'm mistaken) is that you can't refactor iterator methods into smaller chunks - as its complexity grows, the
method will get bigger and bigger and there's nothing you can do about it. The problem is that any methods that you call from an iterator can't themselves yield on behalf of the caller. So if you wanted to do this:
foreach (var foo in far) AnotherMethod (foo);
then AnotherMethod couldn't do anything asynchronous within its implementation.