Я заметил какое-то странное поведение с BackgroundWorkers и событиями, которые они запускают, когда события, кажется, выстраиваются в очередь в одном потоке, в то время как ЦП фактически не используется.
В основном дизайн системы таков, что на основе взаимодействия с пользователем создается поток для отправки веб-запроса на получение некоторых данных. Основываясь на результатах, он может запускать множество других асинхронных запросов, используя BackgroundWorkers для каждого из них. Я делаю это, потому что код, который управляет запросами, использует блокировку, чтобы гарантировать, что только один запрос отправляется за раз (чтобы избежать рассылки спама на сервер несколькими одновременными запросами, что может привести к их игнорированию/блокировке сервером). Для этого может быть лучший дизайн, который я хотел бы услышать (я относительно новичок в программировании на С#/Windows Forms и мог бы воспользоваться советом). Однако, независимо от изменений в дизайне, мне интересно узнать, что вызывает поведение, которое я вижу.
Я написал относительно простое тестовое приложение, чтобы продемонстрировать проблему. По сути, это просто форма с кнопкой и текстовым полем для отображения результатов (вы, вероятно, могли бы сделать это без формы и просто отображать результаты на консоли, но я сделал это таким образом, чтобы воспроизвести то, что делает мое настоящее приложение). Вот код:
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 с между запуском большинства из них).
Кто-нибудь знает, что происходит?