我的问题与在负载增加时阻塞的 aspx.net 4.0 Web 服务器有关。通过阻塞,我的意思是请求是由客户端发送的,但响应会在大约 45 秒后返回。这在开发和生产环境中是可重现的。这 45 秒似乎是恒定的,我在调用 Constructor() 和void Render(HtmlTextWriter writer). 我在一个页面上使用了几个 SqlDataSource 和自定义控件SqlCommand.BeginExecuteReader(...),总共使用了 6 个。如果我用BeginExecuteReader/EndExecuteReader模式停用控件,我可以消除这个问题。所以我假设最终其中一个 BeginExecute 调用被阻塞,直到线程池中的线程可用。
我打印调试消息并识别出一种模式,其中总是在返回阻塞的请求之前打印一堆线程退出消息:
线程 'GetMolFileAsync' (0x1ba4) 已退出,代码为 0 (0x0)。
线程“GetMolFileAsync”(0x27d0) 已退出,代码为 0 (0x0)。
线程 '' (0x23c) 以代码 0 (0x0) 退出。
线程“GetCompoundDepositionInfo”(0x1e88) 已退出,代码为 0 (0x0)。
线程“GetMolFileAsync”(0x2758) 已退出,代码为 0 (0x0)。
0x43 27/07/2012 15:09:42 45 ==>阻塞线程耗时 45 秒
0x5F 27/07/2012 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 秒。对此有何评论?