I'm having trouble with an Async method in C#/.NET 4. It adds threads to the w3wp process, but doesn't release them. Our server eventually reaches a thread limit around 400, and then the app pool becomes unreachable while it recycles.
Are we using EndInvoke wrong here?
Here's a simplified example that repros the problem:
[WebMethod]
public void Test()
{
TestFind("test");
}
private delegate void TestFindDelegate(String val);
private TestFindDelegate tfd;
private IAsyncResult iar;
public void TestFind(String val)
{
try
{
tfd = new TestFindDelegate(this.TestFindAsync);
iar = tfd.BeginInvoke(val, null, null);
}
catch (Exception ex)
{
String msg = ex.Message;
}
}
//Method runs asynchronously
private void TestFindAsync(String val)
{
try
{
//Run stuff here
}
catch (Exception ex)
{
String msg = ex.Message;
}
finally
{
tfd.EndInvoke(iar); //clean up resources
}
}
Steps to Repro:
1. Add code above into a web service.asmx
2. Open Task Manager, add column Threads, find process
3. Open Fiddler, go to Composer, and enter web service url/Test
4. Click Execute 20-40 times
5. Watch the thread count on the process increase, but not decrease.
The problem is likely that you're not calling EndInvoke properly. When using Delegate.BeginInvoke, you must always call EndInvoke, and you must call it after your method is completed. From MSDN:
No matter which technique you use, always call EndInvoke to complete your asynchronous call.
Right now, you're keeping track of tfd and iar in a variable, but each call will overwrite that variable. As such, if you call this 100 times quickly, you'll only call EndInvoke once.
A better option would be to just use Task to run this:
public void TestFind(String val)
{
Task.Factory.StartNew(() => this.TestFindAsync(val));
}
This will call this on a threadpool thread, but not require the EndInvoke call, or any of the local variables to be saved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With