Asynchronous Request Performance using Delegates

Saturday, December 20, 2003 8:17:54 PM (Central Standard Time, UTC-06:00)
One of the reasons this blog is named Discovering .NET, is it seems like that's what I spend a great deal of time doing.  There is not a day that goes by that I don't learn something new about the framework.
 
Today was another one of those days. 
 
I had spent a good part of the day yesterday going through the Async Application Block.  It's really a robust block.  Durable storage of requests that run over a period of time, ability to batch requests and get status on each one in the batch.  Looked like a pretty decent feature set.  It did take some time to get setup, as the actual install instructions were buried in the directory structure.
 
Even though the block would more then meet our needs, it was decided that writing our own implementation to reduce the amount of code surface we would have to maintain would be a better decision.  We were basically looking for a straight forward implementation of a Async batch request.  The Application Block was that and more.  It supported request durability through tables in SQL Server, and required to the installation of two windows services.  One was responsible for requests, while the other was responsible for "garbage collection".  In addition, the data access and exceptions management blocks were leveraged in the implementation.  In all, there was a number of projects involved in the solution.
 
So I forged ahead and implemented a class that would support batch async operations using delegates.  By implementing the batch requests asynchronously, we were hoping to reduce the four requests, each taking 10 seconds (40 seconds for a complete request) to how ever long the longest request took in the batch.
 
What was different about this implementation, it wasn't a "Fire and Forget", nor could I take advantage of a wait handle, as I didn't know which request would take the longest in the batch.
 
I ended up implementing my own blocking code.  The initial cut looked something like this.
 
while(_IsComplete == false) {}
 
It monitored the _IsComplete flag until all requests were complete and the flag was set to true.  Even though the code processed all four requests in about 20 seconds, I expected it to be slightly higher or similar to how long it took to execute just 1 request.  Obviously the first place to look would be at the tight loop I was using to block the thread (the 95% utilization on the CPU might have also given it away).  I tried looking for something similar to what is available in WinForms Application.DoEvents().  I tried the System.Threading.Thread.Sleep(1000), indicating that I wanted to wait for 1 second.  I was able to reduce the total request time to about 14.5 seconds.  I was getting closer.  I noticed that as I reduced the Sleep time, I also reduced the total execution time.  After playing with a couple of scenarios I was able to determine the optimal code:
 
while(_IsComplete == false)
{
     System.Threading.Thread.Sleep(1);
}
 
That's correct, 1 millisecond produced the optimal results, with a final time to process all results at about 9.5 seconds.
 
Yet another discovery today…