просто хочу некоторый совет относительно "лучшей практики" относительно задач многопоточности.
как пример, у нас есть приложение C#, которое после запуска считывает данные с различной таблицы "типа" в нашей базе данных и хранит информацию в наборе, который мы раздаем приложение. это препятствует тому, чтобы мы поразили базу данных каждый раз, когда эта информация запрашивается.
в данный момент приложение считывает данные с 10 таблиц синхронно. я действительно хотел бы прочитать приложение из каждой таблицы в различном потоке все выполнение параллельно. приложение ожидало бы всех потоков для завершения прежде, чем продолжить запуск приложения.
я изучил BackGroundWorker, но просто хочу некоторый совет относительно выполнения вышеупомянутого.
я с нетерпением жду некоторых ответов
Если вы не используете .NET 4.0, вы можете использовать List < ManualResetEvent >, по одному для каждого thread и Подождите , пока они не станут Set . Для ожидания в нескольких потоках вы можете рассмотреть возможность использования WaitAll , но следите за ограничением в 64 дескриптора ожидания. Если вам нужно больше, вы можете просто перебрать их и дождаться каждого по отдельности.
Если вам нужен более быстрый запуск, вам, вероятно, не нужно ждать, пока все данные будут прочитаны во время запуска. Просто отобразите графический интерфейс, и любая отсутствующая информация может быть выделена серым цветом с помощью какого-либо значка «Обновление ...» или аналогичного. Когда информация поступит, просто запустите событие, чтобы обновить графический интерфейс. Пользователь может начать выполнять множество операций еще до того, как будут считаны все данные из всех таблиц.
Если вы любите приключения, вы можете используйте C # 4.0 и параллельную библиотеку задач:
Parallel.ForEach(jobList, curJob => {
curJob.Process()
});
Если у вас более 64 дескрипторов ожидания для потока STA, как говорит Марк. вы можете создать список с вашими потоками и дождаться завершения всех во втором цикле.
//check that all threads have completed.
foreach (Thread thread in threadList)
{
thread.Join();
}
Предполагая, что потоки чтения базы данных возвращаются, как только они закончили, вы можете просто вызвать Thread.Join для всех десяти потоков по очереди из инициирующего потока.
Просто ради забавы, что @Reed сделал с Monitor. : P
class Program
{
static void Main(string[] args)
{
int numThreads = 10;
int toProcess = numThreads;
object syncRoot = new object();
// Start workers.
for (int i = 0; i < numThreads; i++)
{
new Thread(delegate()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
// If we're the last thread, signal
if (Interlocked.Decrement(ref toProcess) == 0)
{
lock (syncRoot)
{
Monitor.Pulse(syncRoot);
}
}
}).Start();
}
// Wait for workers.
lock (syncRoot)
{
if (toProcess > 0)
{
Monitor.Wait(syncRoot);
}
}
Console.WriteLine("Finished.");
}
}
Если вы используете .NET 3.5 или ниже , вы можете использовать массив AsyncResult или BackgroundWorker и подсчитать, сколько потоков вернулось (только не забудьте уменьшить счетчик с блокированными операциями) (см. http://www.albahari.com/threading/ в качестве справки).
Если вы используете .NET 4.0, параллельный подход - это самый простой подход.
Я предпочитаю обрабатывать это с помощью одного WaitHandle и использовать Interlocked, чтобы избежать блокировки счетчика:
class Program
{
static void Main(string[] args)
{
int numThreads = 10;
ManualResetEvent resetEvent = new ManualResetEvent(false);
int toProcess = numThreads;
// Start workers.
for (int i = 0; i < numThreads; i++)
{
new Thread(delegate()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
// If we're the last thread, signal
if (Interlocked.Decrement(ref toProcess) == 0)
resetEvent.Set();
}).Start();
}
// Wait for workers.
resetEvent.WaitOne();
Console.WriteLine("Finished.");
}
}
Это работает хорошо и масштабируется до любого числа потоков, обрабатываемых без введения блокировки.
Мне нравится решение @Reed. Другой способ добиться того же в .NET 4.0 - использовать CountdownEvent .
class Program
{
static void Main(string[] args)
{
var numThreads = 10;
var countdownEvent = new CountdownEvent(numThreads);
// Start workers.
for (var i = 0; i < numThreads; i++)
{
new Thread(delegate()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
// Signal the CountdownEvent.
countdownEvent.Signal();
}).Start();
}
// Wait for workers.
countdownEvent.Wait();
Console.WriteLine("Finished.");
}
}