线程池不足
本文关键字:线程 | 更新日期: 2024-07-27 13:26:59
我的问题与aspx.net 4.0 web服务器在负载增加的情况下阻塞有关。通过阻塞我的意思是,请求是由客户端发送的,但大约45秒后返回响应。这在开发和生产环境中是可复制的。这45秒似乎是恒定的,我在客户端和aspx页面上测量了调用Constructor()和void Render(HtmlTextWriter writer)
之间的时间。我同时使用了几个SqlDataSource和自定义控件,在一个页面上总共使用了6个SqlCommand.BeginExecuteReader(...)
。如果我使用BeginExecuteReader
/EndExecuteReader
模式停用控件,我可以消除问题。因此,我假设最终有一个BeginExecute调用被阻止,直到线程池中有一个线程可用。
我打印调试消息,并识别出一种模式,即总是在返回被阻止的请求之前打印一堆线程退出消息:
线程"GetMolFileAsync"(0x1ba4)已退出,代码为0(0x0)。
线程"GetMolFileAsync"(0x27d0)已退出,代码为0(0x0)。
线程"(0x23c)已退出,代码为0(0x0)。
线程"GetComponentDepositionInfo"(0x1e88)已退出,代码为0(0x0)。
线程"GetMolFileAsync"(0x2758)已退出,代码为0(0x0)。
0x43 2012年7月27日15:09:42 45==>阻塞线程耗时45秒
0x5F 2012年7月27日15:10:27 0==>正常行为,在几毫秒内处理
这是向数据库发起请求的方法
public static IAsyncResult GetCompoundDepositionInfoAsync(object sender, EventArgs e, AsyncCallback callback, object state)
{
GetCompoundVersionInfoAsyncParameters parameters = (GetCompoundVersionInfoAsyncParameters)state;
IAsyncResult res = null;
parameters.cmd = new System.Data.SqlClient.SqlCommand("www.GetCompoundDepositionInfo", new System.Data.SqlClient.SqlConnection(parameters.connectionstring));
parameters.cmd.CommandType = System.Data.CommandType.StoredProcedure;
parameters.cmd.Parameters.AddWithValue("@CompoundID", parameters.CompoundID);
try
{
parameters.cmd.Connection.Open();
res = parameters.cmd.BeginExecuteReader(callback, parameters, System.Data.CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
if (parameters.cmd.Connection.State == System.Data.ConnectionState.Open)
{
parameters.cmd.Connection.Close();
}
throw new Exception("Exception in calling GetCompoundDepositionInfoAsync()", ex);
}
return res;
}
这是回调函数
public void GetCompoundDepositionInfoCallback(IAsyncResult result)
{
gmdTools.GmdCompound.GetCompoundVersionInfoAsyncParameters param = (gmdTools.GmdCompound.GetCompoundVersionInfoAsyncParameters)result.AsyncState;
System.Threading.Thread.CurrentThread.Name = "GetCompoundDepositionInfo";
using(System.Data.SqlClient.SqlCommand command = param.cmd)
using(System.Data.SqlClient.SqlDataReader reader = command.EndExecuteReader(result))
{
try
{
if (reader.Read())
{
lblDeposited.Text = string.Concat("at ", reader.GetDateTime(0).ToShortDateString(), " by ", reader.GetString(1));
}
}
finally
{
if (reader != null)
{
reader.Close();
command.Connection.Close();
}
}
}
}
这是把它们粘在一起的代码。。。
Page.RegisterAsyncTask(new PageAsyncTask(
new BeginEventHandler(gmdTools.GmdCompound.GetCompoundLastChangeInfoAsync)
, new EndEventHandler(GetCompoundLastChangeInfoCallback)
, new EndEventHandler(GetCompoundInfoAsyncTimeout)
, new gmdTools.GmdCompound.GetCompoundVersionInfoAsyncParameters()
{
connectionstring = Properties.Settings.Default.GmdConnectionString,
CompoundID = CompoundId,
}, true
));
由于我已经花了几个小时研究这个代码,如果有任何反馈,我将不胜感激。
更新这45秒由默认的Page.AsyncTimeout
推断,并且可以使用Async="true" AsyncTimeout="10"
语句将其更改为10秒。尽管我通过添加适当的索引大大提高了网站的整体性能,但在服务器发送响应之前,客户端通常需要等待这么长时间。在这种情况下,不会调用AsyncTimeout
处理程序。我假设页面注册了所有异步操作,但最终没有识别出某些异步操作已成功完成,因此在呈现页面之前等待AsyncTimeout秒。对此有何评论?
它可能是数据库,给定查询返回的一个或多个行,它选择的是多于还是少于千分之一?当选择通过返回的1000行中的1行时,MSSQL将更改其操作方式。如果使用SQL探查器运行查询,会得到表扫描吗?如果运行用于确定缺少索引的内置sp,它是否会返回对这些表的索引的请求?你的统计数据是最新的吗?线索是,恢复的备份会快速运行查询,因为当您恢复备份时,统计信息会更新。您的(所有/每个)表上都有聚集索引吗?
此外,这个答案可能与实体框架MVC慢速页面加载有关
您是否在连接字符串中使用async=true属性。这对于使用SqlClient的真正异步操作是必需的。如果可能的话,你可以在.Net 4.5上使用任务异步功能尝试一下,代码如下。
public async Task GetCompoundDepositionInfoAsync(CancellationToken cancellationToken)
{
parameters.cmd = new System.Data.SqlClient.SqlCommand("www.GetCompoundDepositionInfo", new System.Data.SqlClient.SqlConnection(parameters.connectionstring));
parameters.cmd.CommandType = System.Data.CommandType.StoredProcedure;
parameters.cmd.Parameters.AddWithValue("@CompoundID", parameters.CompoundID);
using (var connection = new SqlConnection(parameters.connectionstring))
using (var command = new SqlCommand(query, connection))
{
await connection.OpenAsync(cancellationToken);
using (var reader = await command.ExecuteReaderAsync(cancellationToken))
{
if (await reader.ReadAsync(cancellationToken))
{
lblDeposited.Text = string.Concat("at ", reader.GetDateTime(0).ToShortDateString(), " by ", reader.GetString(1));
}
}
}
}
和在page_load()中
RegisterAsyncTask(new PageAsyncTask(GetCompoundDepositionInfoAsync));