D
Dan Battagin
Is there a known bug with the interaction between the HttpWebRequest and the
ThreadPool? I current spawn several HttpWebRequest's using
BeginGetResponse, and they work for a while, using worker threads from the
ThreadPool. However, eventually (relatively quickly) there become fewer and
fewer available worker threads in the pool, until there are 0 and a
System.InvalidOperationException occurs with the message: "There were not
enough free threads in the ThreadPool object to complete the operation."
It's as if the worker threads are never released by the HttpWebRequest,
which seems like a pretty serious bug.
Oh, and so far I only repro this on Win9x (ME to be precise, haven't tried
98 yet). The worker threads seem to be released fine by all of the NT
flavors.
Below I am including 2 things:
(a) The methods that work with the HttpWebRequest object
(b) The result of calling ThreadPool.GetAvailableThreads(out int
workerThreads, out int completionPortThreads) as I create each
HttpWebRequest (until the number of workers hits 0 at which point an
exception is thrown)
Thanks,
Dan
(a) basically I call these in a loop, such that no more than 8 are active
at any given time
public void BeginScrapeContent(ScraperConfig config) {
if (config == null) {
if (_config == null) {
throw new ArgumentNullException("config", "config or _config can not
be null.");
}
} else {
this._config = config;
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Url);
request.BeginGetResponse(new AsyncCallback(EndRequestContent1), request);
}
private void EndRequestContent1(IAsyncResult ar) {
HttpWebRequest request = null;
try {
request = (HttpWebRequest)ar.AsyncState;
request.EndGetResponse(ar);
_content += new
StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
_contentRetrievalSuccess1 = true;
} catch (Exception ex) {
_contentRetrievalSuccess1 = false;
Debug.WriteLine(ex.Message);
_failReason = ex is WebException ? ContentRetrievalFailure.NoResponse :
ContentRetrievalFailure.BadResponse;
} finally {
try {
request.GetResponse().Close();
} catch {
Debug.WriteLine("Error calling close");
}
}
}
(b) Here's the result, of in that loop where I call the BeginScrapeContent
method), checking ThreadPool.GetAvailableThreads each time I perform a new
BeginScrapeContent call (again, there are ever only a max of 8 of these at
any time). As you can see the number of worker threads drops to 0 quite
quickly.
wrkThrds: 25 cpThrds: 25
wrkThrds: 25 cpThrds: 25
wrkThrds: 24 cpThrds: 25
wrkThrds: 24 cpThrds: 25
wrkThrds: 23 cpThrds: 25
wrkThrds: 21 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 16 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 15 cpThrds: 25
wrkThrds: 16 cpThrds: 25
wrkThrds: 16 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 15 cpThrds: 25
wrkThrds: 15 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 6 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 4 cpThrds: 25
wrkThrds: 3 cpThrds: 25
wrkThrds: 3 cpThrds: 25
wrkThrds: 1 cpThrds: 25
wrkThrds: 0 cpThrds: 25
Exception Type: System.InvalidOperationException
Message: There were not enough free threads in the ThreadPool object to
complete the operation.
Stack Trace:
at System.Net.HttpWebRequest.BeginGetResponse(AsyncCallback callback,
Object state)
at TestApp.Retriever.BeginScrapeContent(ScraperConfig config)
at TestApp.Form1.RetrieveContentStart()
Source: System
Target Site: System.IAsyncResult BeginGetResponse(System.AsyncCallback,
System.Object)
ThreadPool? I current spawn several HttpWebRequest's using
BeginGetResponse, and they work for a while, using worker threads from the
ThreadPool. However, eventually (relatively quickly) there become fewer and
fewer available worker threads in the pool, until there are 0 and a
System.InvalidOperationException occurs with the message: "There were not
enough free threads in the ThreadPool object to complete the operation."
It's as if the worker threads are never released by the HttpWebRequest,
which seems like a pretty serious bug.
Oh, and so far I only repro this on Win9x (ME to be precise, haven't tried
98 yet). The worker threads seem to be released fine by all of the NT
flavors.
Below I am including 2 things:
(a) The methods that work with the HttpWebRequest object
(b) The result of calling ThreadPool.GetAvailableThreads(out int
workerThreads, out int completionPortThreads) as I create each
HttpWebRequest (until the number of workers hits 0 at which point an
exception is thrown)
Thanks,
Dan
(a) basically I call these in a loop, such that no more than 8 are active
at any given time
public void BeginScrapeContent(ScraperConfig config) {
if (config == null) {
if (_config == null) {
throw new ArgumentNullException("config", "config or _config can not
be null.");
}
} else {
this._config = config;
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Url);
request.BeginGetResponse(new AsyncCallback(EndRequestContent1), request);
}
private void EndRequestContent1(IAsyncResult ar) {
HttpWebRequest request = null;
try {
request = (HttpWebRequest)ar.AsyncState;
request.EndGetResponse(ar);
_content += new
StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
_contentRetrievalSuccess1 = true;
} catch (Exception ex) {
_contentRetrievalSuccess1 = false;
Debug.WriteLine(ex.Message);
_failReason = ex is WebException ? ContentRetrievalFailure.NoResponse :
ContentRetrievalFailure.BadResponse;
} finally {
try {
request.GetResponse().Close();
} catch {
Debug.WriteLine("Error calling close");
}
}
}
(b) Here's the result, of in that loop where I call the BeginScrapeContent
method), checking ThreadPool.GetAvailableThreads each time I perform a new
BeginScrapeContent call (again, there are ever only a max of 8 of these at
any time). As you can see the number of worker threads drops to 0 quite
quickly.
wrkThrds: 25 cpThrds: 25
wrkThrds: 25 cpThrds: 25
wrkThrds: 24 cpThrds: 25
wrkThrds: 24 cpThrds: 25
wrkThrds: 23 cpThrds: 25
wrkThrds: 21 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 16 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 15 cpThrds: 25
wrkThrds: 16 cpThrds: 25
wrkThrds: 16 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 13 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 12 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 18 cpThrds: 25
wrkThrds: 19 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 17 cpThrds: 25
wrkThrds: 15 cpThrds: 25
wrkThrds: 15 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 14 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 11 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 9 cpThrds: 25
wrkThrds: 10 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 8 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 7 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 6 cpThrds: 25
wrkThrds: 5 cpThrds: 25
wrkThrds: 4 cpThrds: 25
wrkThrds: 3 cpThrds: 25
wrkThrds: 3 cpThrds: 25
wrkThrds: 1 cpThrds: 25
wrkThrds: 0 cpThrds: 25
Exception Type: System.InvalidOperationException
Message: There were not enough free threads in the ThreadPool object to
complete the operation.
Stack Trace:
at System.Net.HttpWebRequest.BeginGetResponse(AsyncCallback callback,
Object state)
at TestApp.Retriever.BeginScrapeContent(ScraperConfig config)
at TestApp.Form1.RetrieveContentStart()
Source: System
Target Site: System.IAsyncResult BeginGetResponse(System.AsyncCallback,
System.Object)