CPU が実際に使用されていないときに、イベントが 1 つのスレッドでキューに入っているように見える場合、BackgroundWorkers とそれらが起動するイベントの奇妙な動作に気付きました。
システムの基本的な設計は、ユーザーの操作に基づいてスレッドが作成され、Web 要求を送信してデータをフェッチするというものです。結果に基づいて、それぞれに対して BackgroundWorkers を使用して、他の多くの非同期リクエストを開始する場合があります。私がこれを行っているのは、リクエストを管理するコードがロックを使用して、一度に 1 つのリクエストのみが送信されるようにするためです (複数の同時リクエストでサーバーにスパムを送信し、サーバーがそれらを無視/ブロックする可能性があるため)。これにはもっと良い設計があるかもしれません.それを聞いてみたいです. ただし、デザインの変更に関係なく、私が見ている動作の原因を知りたいと思っています。
この問題を実証するために、比較的単純なテスト アプリを作成しました。これは基本的に、結果を表示するためのボタンとテキスト ボックスを備えた単なるフォームです (おそらく、フォームを使用せずにコンソールに結果を表示することもできますが、実際のアプリの動作を再現するためにこのようにしました)。コードは次のとおりです。
delegate void AddToLogCallback(string str);
private void AddToLog(string str)
{
if(textBox1.InvokeRequired)
{
AddToLogCallback callback = new AddToLogCallback(AddToLog);
Invoke(callback, new object[] { str });
}
else
{
textBox1.Text += DateTime.Now.ToString() + " " + str + System.Environment.NewLine;
textBox1.Select(textBox1.Text.Length, 0);
textBox1.ScrollToCaret();
}
}
private void Progress(object sender, ProgressChangedEventArgs args)
{
AddToLog(args.UserState.ToString());
}
private void Completed(object sender, RunWorkerCompletedEventArgs args)
{
AddToLog(args.Result.ToString());
}
private void DoWork(object sender, DoWorkEventArgs args)
{
BackgroundWorker worker = sender as BackgroundWorker;
lock (typeof(Form1)) // Ensure only a single request at a time
{
worker.ReportProgress(0, "Start");
Thread.Sleep(2000); // Simulate waiting on the request
worker.ReportProgress(50, "Middle");
Thread.Sleep(2000); // Simulate handling the response from the request
worker.ReportProgress(100, "End");
args.Result = args.Argument;
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(RunMe);
thread.Start();
}
private void RunMe()
{
for(int i=0; i < 20; i++)
{
AddToLog("Starting " + i.ToString());
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += DoWork;
worker.RunWorkerCompleted += Completed;
worker.ProgressChanged += Progress;
worker.RunWorkerAsync(i);
}
}
戻ってきた結果は次のとおりです。
30/07/2009 2:43:22 PM Starting 0
30/07/2009 2:43:22 PM Starting 1
<snip>
30/07/2009 2:43:22 PM Starting 18
30/07/2009 2:43:22 PM Starting 19
30/07/2009 2:43:23 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:36 PM End
30/07/2009 2:43:36 PM 0
30/07/2009 2:43:36 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:36 PM End
30/07/2009 2:43:36 PM 1
30/07/2009 2:43:36 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:36 PM End
30/07/2009 2:43:36 PM 8
30/07/2009 2:43:36 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:38 PM 13
30/07/2009 2:43:38 PM End
30/07/2009 2:43:38 PM Start
30/07/2009 2:43:40 PM Middle
30/07/2009 2:43:42 PM 18
30/07/2009 2:43:42 PM Start
30/07/2009 2:43:42 PM End
30/07/2009 2:43:44 PM Middle
30/07/2009 2:43:46 PM End
30/07/2009 2:43:46 PM 2
30/07/2009 2:43:46 PM Start
30/07/2009 2:43:48 PM Middle
ご覧のとおり、最初の「開始」メッセージが表示されてから 13 秒の遅延があり、その後約 15 個のメッセージを処理します (ほとんどのメッセージが起動されるまでに 2 秒の遅延があるにもかかわらず)。
何が起こっているか知っている人はいますか?