我在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.观察过程增加的线程数,但不减少。
答案 0 :(得分:2)
问题可能是你没有正确地调用EndInvoke
。使用Delegate.BeginInvoke
时,您必须始终致电EndInvoke
,并且必须在方法完成后将其命名为。来自MSDN:
无论使用哪种技术,都要调用EndInvoke来完成异步调用。
现在,您在变量中跟踪tfd
和iar
,但每次调用都会覆盖该变量。因此,如果您快速拨打100次,则只需拨打EndInvoke
一次。
更好的选择是使用Task
来运行它:
public void TestFind(String val)
{
Task.Factory.StartNew(() => this.TestFindAsync(val));
}
这将在线程池线程上调用它,但不需要EndInvoke
调用,或者要保存任何局部变量。