HttpWebRequest - you're using the thread pool, and you may not know

System.Net.WebRequest is a damn useful class for putting data back from a Web server.  However, if you did into its code, you can find a weird design decision that may have a significant impact for those writing certain kinds of applications.

Here's some quick and dirty code for connecting to a server and pulling back the complete response into a string:

// make a request...
WebRequest request = WebRequest.Create("http://www.dotnet247.com/");

// let's get some data...
WebResponse response = null;
Stream stream = null;
try
{
   
// get a response...
    response =
request.GetResponse();

    // get the stream...
   
stream = response.GetResponseStream();

    // read it...
   
StreamReader reader = new StreamReader(stream);

    // get it all...
   
string htmlResult = reader.ReadToEnd();

    // how long?
   
MessageBox.Show(this, string.Format("Got {0} char(s).", htmlResult.Length));
}
finally
{
   
// cleanup...
   
if(stream != null)
       
stream.Close();
    if(response != null)
       
response.Close();
}

Looks fairly innocent doesn't it?  This looks as single-threaded as they come, but the thing to watch here is that under the hood, this code is actually multi-threaded.  WebRequest.Create returns, in this case, a HttpWebRequest class, which inherits from WebRequest.  WebRequest supports BeginGetResponse and EndGetResponse which can be used to make asynchronous requests to an HTTP resource. 

If you Reflect into GetResponse using Reflector, you get this code:

public override WebResponse GetResponse()
{
    IAsyncResult result1;
    if (this._HaveResponse)
    {
         this.CheckFinalStatus();
         if (this._HttpResponse != null)
        {
             return this._HttpResponse;
        } 
    }
    result1 = base.BeginGetResponse(null, null);
    if ((this._Timeout != -1) && !result1.IsCompleted)
    {
        result1.AsyncWaitHandle.WaitOne(this._Timeout, 0);
        if (!result1.IsCompleted)
       {
            base.Abort();
            throw new WebException(SR.GetString("net_timeout"), 14);
       } 
    }
    return base.EndGetResponse(result1);
}

You can see that this code is unconditionally calling BeginGetResponse.  This means that the request is always made asynchronously via the thread pool, even though we're running in a single-threaded mode.

In desktop applications, you're very rarely going to care about this, because you're quite unlikely to be using the thread pool heavily enough that you run into starvation issues.  However, if you're server side, it's much more likely that you will be using the thread pool heavily enough for this to become a problem. 

This, to me, is a great example of why in .NET it's actually quite important to investigate classes that are key to the solution you're building to garner data on possible problems.  In this case, this came about because a client of mine was writing a server side application to gather responses from multiple Web services simultaneously.  Having the knowledge that what appears to be a chunk of code that uses a single thread in fact using two was invaluable in this case at informing our design decisions at an early stage.

1 Comment

  • Hi,
    can u pls explain Thread Pool Starvation problem and possible causes for the same as well resolution to the same...

    Thanks
    Nick

Comments have been disabled for this content.