Мечите икру Несколько Потоков для работы затем ожидают до всех законченных

просто хочу некоторый совет относительно "лучшей практики" относительно задач многопоточности.

как пример, у нас есть приложение C#, которое после запуска считывает данные с различной таблицы "типа" в нашей базе данных и хранит информацию в наборе, который мы раздаем приложение. это препятствует тому, чтобы мы поразили базу данных каждый раз, когда эта информация запрашивается.

в данный момент приложение считывает данные с 10 таблиц синхронно. я действительно хотел бы прочитать приложение из каждой таблицы в различном потоке все выполнение параллельно. приложение ожидало бы всех потоков для завершения прежде, чем продолжить запуск приложения.

я изучил BackGroundWorker, но просто хочу некоторый совет относительно выполнения вышеупомянутого.

  1. Делает звук метода, логичный для ускорения времени запуска нашего приложения
  2. Как мы можем лучше всего обработать все потоки, имеющие в виду, что работа каждого потока независима друг от друга, мы просто должны ожидать всех потоков для завершения перед продолжением.

я с нетерпением жду некоторых ответов

53
задан Erik Philips 19 April 2014 в 15:50
поделиться

8 ответов

Если вы не используете .NET 4.0, вы можете использовать List < ManualResetEvent >, по одному для каждого thread и Подождите , пока они не станут Set . Для ожидания в нескольких потоках вы можете рассмотреть возможность использования WaitAll , но следите за ограничением в 64 дескриптора ожидания. Если вам нужно больше, вы можете просто перебрать их и дождаться каждого по отдельности.

Если вам нужен более быстрый запуск, вам, вероятно, не нужно ждать, пока все данные будут прочитаны во время запуска. Просто отобразите графический интерфейс, и любая отсутствующая информация может быть выделена серым цветом с помощью какого-либо значка «Обновление ...» или аналогичного. Когда информация поступит, просто запустите событие, чтобы обновить графический интерфейс. Пользователь может начать выполнять множество операций еще до того, как будут считаны все данные из всех таблиц.

7
ответ дан 7 November 2019 в 08:22
поделиться

Если вы любите приключения, вы можете используйте C # 4.0 и параллельную библиотеку задач:

Parallel.ForEach(jobList, curJob => {
  curJob.Process()
});
6
ответ дан 7 November 2019 в 08:22
поделиться

Если у вас более 64 дескрипторов ожидания для потока STA, как говорит Марк. вы можете создать список с вашими потоками и дождаться завершения всех во втором цикле.

//check that all threads have completed.
foreach (Thread thread in threadList)
{
     thread.Join();

}  
9
ответ дан 7 November 2019 в 08:22
поделиться

Предполагая, что потоки чтения базы данных возвращаются, как только они закончили, вы можете просто вызвать Thread.Join для всех десяти потоков по очереди из инициирующего потока.

1
ответ дан 7 November 2019 в 08:22
поделиться

Просто ради забавы, что @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.");
    }
}
2
ответ дан 7 November 2019 в 08:22
поделиться

Если вы используете .NET 3.5 или ниже , вы можете использовать массив AsyncResult или BackgroundWorker и подсчитать, сколько потоков вернулось (только не забудьте уменьшить счетчик с блокированными операциями) (см. http://www.albahari.com/threading/ в качестве справки).

Если вы используете .NET 4.0, параллельный подход - это самый простой подход.

0
ответ дан 7 November 2019 в 08:22
поделиться

Я предпочитаю обрабатывать это с помощью одного 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.");
    }
}

Это работает хорошо и масштабируется до любого числа потоков, обрабатываемых без введения блокировки.

91
ответ дан 7 November 2019 в 08:22
поделиться

Мне нравится решение @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.");
    }
}
28
ответ дан 7 November 2019 в 08:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: