私の問題は、負荷が増加した場合のaspx.net4.0Webサーバーのブロックに関連しています。ブロックとは、リクエストがクライアントによって送信されたが、応答が約45秒後に返されることを意味します。これは、開発および実稼働環境で再現可能です。この45秒は一定のようで、Constructor()との呼び出しの間のクライアントとaspxページの両方でこれを測定しましたvoid Render(HtmlTextWriter writer)
。SqlCommand.BeginExecuteReader(...)
私は、いくつかのSqlDataSourceと、1ページで合計6つを利用するカスタムメイドのコントロールの両方を使用しています。BeginExecuteReader
/EndExecuteReader
パターンでコントロールを非アクティブ化すると、問題を解決できます。したがって、スレッドがThreadPoolで使用可能になるまで、最終的にBeginExecute呼び出しの1つがブロックされると想定します。
デバッグメッセージを出力し、ブロックされた要求が返される直前に常に一連のスレッド終了メッセージが出力されるパターンを認識しました。
スレッド'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:4245==>ブロックされたスレッドは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
));
私はすでにこのコードを見て何時間も費やしたので、フィードバックをいただければ幸いです。
UPDATE
この45秒はデフォルトで推論され、ステートメントPage.AsyncTimeout
を使用して10秒に変更できます。Async="true" AsyncTimeout="10"
適切なインデックスを追加することでサイトの全体的なパフォーマンスを大幅に向上させましたが、サーバーが応答を送信する前に、クライアントがこの時間待機しなければならない場合があります。この場合、AsyncTimeout
ハンドラーは呼び出されません。ページはすべての非同期操作を登録していると思いますが、最終的には一部の非同期操作が正常に完了したことを認識しないため、ページをレンダリングする前にAsyncTimeout秒待機します。それについて何かコメントはありますか?