异步线程未发布

时间:2013-06-12 22:50:46

标签: c# .net asynchronous

我在C#/ .NET 4中遇到了Async方法的问题。它为w3wp进程添加了线程,但是没有释放它们。我们的服务器最终达到大约400的线程限制,然后应用程序池在回收时变得无法访问。

我们在这里使用EndInvoke是错误的吗?

以下是重新解决问题的简化示例:

    [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
        }
    }

Repro的步骤:
 1.将上面的代码添加到web service.asmx中  2.打开任务管理器,添加列线程,查找进程
 3.打开Fiddler,转到Composer,然后输入Web服务URL /测试
 4.单击执行20-40次
 5.观察过程增加的线程数,但不减少。

1 个答案:

答案 0 :(得分:2)

问题可能是你没有正确地调用EndInvoke。使用Delegate.BeginInvoke时,您必须始终致电EndInvoke,并且必须在方法完成后将其命名为。来自MSDN

  

无论使用哪种技术,都要调用EndInvoke来完成异步调用。

现在,您在变量中跟踪tfdiar,但每次调用都会覆盖该变量。因此,如果您快速拨打100次,则只需拨打EndInvoke一次。

更好的选择是使用Task来运行它:

public void TestFind(String val)
{
    Task.Factory.StartNew(() => this.TestFindAsync(val));
}

这将在线程池线程上调用它,但不需要EndInvoke调用,或者要保存任何局部变量。