I have an ASP.NET MVC web application that makes REST style web service calls to other servers. I have a scenario where I am making two HttpWebRequest calls to two separate services. I need them both to complete to continue, but their order doesn’t matter. They may take 1-2 seconds each and I am running them in sequence now. Running them in parallel would decrease the user response time, but what is the best way?
In researching this, I can think of several options:
- Execute one request on the main thread, and spin up a second thread for the other request. Should created new threads or use a thread pool? If I use a pool, how do I size it? Also, not sure how I can join the threads back together (e.g. use ThreadPool.RegisterWaitForSingleObject)?
- Try and leverage the built-in IAsyncResult support for one or both of the requests. Again, not sure on which threads the async request execute, so not sure how to size the thread pool. How do I join IAsyncResult back into my main thread? All the examples I find process information in the callback, but I can just wait in my main thread and use the IsCompleted property?
I need to find a solution that will both function, and perform at scale. That is why I am worried about thread pool sizing. I would hate to have requests blocking because they are waiting for available threads.
One of the answers to Multithreading WebRequests, a good and stable approach? : CSharp uses a
ManualResetEvent event = new ManualResetEvent(), a reference counter equaling the number of in flight requests andInterlocked.Decrementto control theevent.Set(). The main thread then waits by callingevent.WaitOne().However, WaitHandles – Auto/ManualResetEvent and Mutex mentions that ManualResetEvent “can be significantly slower than using the various Monitor methods” like Wait, Pulse and PulseAll.
I ended up basing my code off of this Noah Blumenthal blog post: Run generic tasks async (fluent-ly). I did make two changes: implement
IDisposableand call.Close()on theManualResetEventand switch from using alock()toInterlocked.Increment()and.Decrement().