Я пытаюсь создать инструмент Windows Forms, который выполняет запросы асинхронно. Приложение имеет datagridview с 30 возможными запросами для запуска. Пользователь проверяет запросы, которые он хочет выполнить, например, 10 запросов и нажатие кнопки. Приложение имеет переменную maxthreads = 3 (для обсуждения), которая указывает, сколько потоков можно использовать для асинхронного запуска запросов. Запросы выполняются в рабочей среде, и мы не хотим перегружать систему слишком большим количеством потоков, запущенных в одно и то же время. Каждый запрос выполняется в среднем 30 секунд. (около 5 минут, другие 2 сек.) В datagridview есть столбец изображений, содержащий значок, который отображает состояние каждого запроса (0- Доступно для запуска, 1-Выбран для запуска, 2- Запуск, 3- Успешно завершено, -1 Ошибка) Мне нужно иметь возможность общаться с пользовательским интерфейсом каждый раз, когда запрос начинается и заканчивается. Как только запрос заканчивается, результаты отображаются в представлении datagridview, содержащемся в Tabcontrol (одна вкладка для каждого запроса).Создайте многопоточные приложения для запуска нескольких запросов в C#
Подход: Я думал создать несколько рабочих фонарей maxthread и позволить им запускать запросы. По завершении работы фонового работ он взаимодействует с пользовательским интерфейсом и назначается новому запросу и так далее, пока не будут выполнены все запросы.
Я пробовал использовать jobWorker, который отправил бы работу работникам фона, но не знает, как ждать завершения всех потоков. После завершения bgw он сообщает о прогрессе в событии RunWorkerCompleted в jobWorker, но тот уже завершен.
В потоке пользовательского интерфейса я называю работник присваивания со всеми запросами, которые необходимо выполнить:
private void btnRunQueries_Click(object sender, EventArgs e)
{
if (AnyQueriesSelected())
{
tcResult.TabPages.Clear();
foreach (DataGridViewRow dgr in dgvQueries.Rows)
{
if (Convert.ToBoolean(dgr.Cells["chk"].Value))
{
Query q = new Query(dgr.Cells["ID"].Value.ToString(),
dgr.Cells["Name"].Value.ToString(),
dgr.Cells["FileName"].Value.ToString(),
dgr.Cells["ShortDescription"].Value.ToString(),
dgr.Cells["LongDescription"].Value.ToString(),
dgr.Cells["Level"].Value.ToString(),
dgr.Cells["Task"].Value.ToString(),
dgr.Cells["Importance"].Value.ToString(),
dgr.Cells["SkillSet"].Value.ToString(),
false,
new Dictionary<string, string>()
{ { "#ClntNb#", txtClntNum.Text }, { "#Staff#", "100300" } });
qryList.Add(q);
}
}
assignmentWorker.RunWorkerAsync(qryList);
}
else
{
MessageBox.Show("Please select at least one query.",
"Warning",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
Вот AssignmentWorker:
private void assignmentWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Query q in (List<Query>)e.Argument)
{
while (!q.Processed)
{
for (int threadNum = 0; threadNum < maxThreads; threadNum++)
{
if (!threadArray[threadNum].IsBusy)
{
threadArray[threadNum].RunWorkerAsync(q);
q.Processed = true;
assignmentWorker.ReportProgress(1, q);
break;
}
}
//If all threads are being used, sleep awhile before checking again
if (!q.Processed)
{
Thread.Sleep(500);
}
}
}
}
Все BGW запустить то же событие:
private void backgroundWorkerFiles_DoWork(object sender, DoWorkEventArgs e)
{
try
{
Query qry = (Query)e.Argument;
DataTable dtNew = DataAccess.RunQuery(qry).dtResult;
if (dsQryResults.Tables.Contains(dtNew.TableName))
{
dsQryResults.Tables.Remove(dtNew.TableName);
}
dsQryResults.Tables.Add(dtNew);
e.Result = qry;
}
catch (Exception ex)
{
}
}
После того, как запрос вернулся и DataTable был добавлен в набор данных:
private void backgroundWorkerFiles_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
try
{
if (e.Error != null)
{
assignmentWorker.ReportProgress(-1, e.Result);
}
else
{
assignmentWorker.ReportProgress(2, e.Result);
}
}
catch (Exception ex)
{
int o = 0;
}
}
У меня есть проблема в том, что работник присваивание заканчивается до финиша BGW и призыв к assignmentWorker.ReportProgress идти в ад (простите мой французский). Как я могу дождаться завершения всех запущенных bgw до завершения работника задания?
Спасибо!
Я бы не разделил его на рабочего рабочего фона и рабочих назначений, это слишком сложно для этой задачи. вы можете иметь фоновый поток, который 'foreach'' 'queries to run' должен начинать работу с ThreadPool или ждать, пока число рабочих потоков будет меньше' maxthreads', и цикл, пока не будут выполнены все запросы к процессу. Чтобы отобразить результаты, фоновая задача должна завершиться соответствующими обновлениями в пользовательском интерфейсе с помощью 'Dispatcher', чтобы начать работу с основным потоком пользовательского интерфейса. – Mobigital