简体   繁体   中英

Async Threads Not Released

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM