Как лучше всего передавать данные между параллельными потоками в .NET?
-
01-07-2019 - |
Вопрос
У меня есть два потока, один нужно опросить кучу отдельных статических ресурсов в поисках обновлений.Другой должен получить данные и сохранить их в базе данных.Как поток 1 может сообщить потоку 2, что есть что-то для обработки?
Решение
Если фрагменты данных независимы, рассматривайте их как рабочие элементы, которые будут обрабатываться пулом потоков.Используйте пул потоков и QueueUserWorkItem
для публикации данных в теме(ях).Вы должны добиться лучшей масштабируемости, используя пул симметричных потоков и ограничивая объем синхронизации, которая должна происходить между производителем и потребителем(ями).
Например (из MSDN):
TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);
// Queue the task and data.
if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti)) {
Console.WriteLine("Main thread does some work, then sleeps.");
// If you comment out the Sleep, the main thread exits before
// the ThreadPool task has a chance to run. ThreadPool uses
// background threads, which do not keep the application
// running. (This is a simple example of a race condition.)
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
else {
Console.WriteLine("Unable to queue ThreadPool request.");
}
// The thread procedure performs the independent task, in this case
// formatting and printing a very simple report.
//
static void ThreadProc(Object stateInfo) {
TaskInfo ti = (TaskInfo) stateInfo;
Console.WriteLine(ti.Boilerplate, ti.Value);
}
Другие советы
Я использую Monitor.Wait/Pulse в очереди рабочих элементов.
Всегда ли должен быть запущен поток «хранить в БД»?Похоже, что лучшим вариантом (если это возможно) было бы заставить поток опроса запустить другой поток для сохранения.Однако в зависимости от количества создаваемых потоков может оказаться, что использование первого потока опроса ThreadPool.QueueUserWorkItem() может быть более эффективным маршрутом.
Для большей эффективности при сохранении в базе данных я бы использовал асинхронный ввод-вывод в БД, а не методы синхронизации.
В любой момент, когда вы можете избежать необходимости прямого взаимодействия между двумя потоками, вам следует это сделать.Из-за необходимости собрать воедино некоторые примитивы синхронизации ваш код будет не так легко отлаживать, и он может привести к появлению некоторых очень тонких условий гонки, которые вызывают ошибки типа «выполнение один раз на миллион» (находить/исправлять которые далеко не весело).
Если второй поток всегда должен выполняться, сообщите нам, почему, предоставив дополнительную информацию, и мы сможем дать более подробный ответ.
Удачи!
Лично я бы хотел, чтобы поток 1 вызывал события, на которые мог бы ответить поток 2.Потоки могут быть связаны с соответствующими событиями управляющим процессом, который инициирует оба потока.