Тема против ThreadPool

В чем разница между использованием нового потока и использованием потока из пула потоков? Какие преимущества в производительности и почему я должен рассмотреть использование потока из пула, а не одного, который я явно создал? Я имею в виду конкретно.NET здесь, но общие примеры в порядке.

10 ответов

Решение

Пул потоков обеспечит преимущества для частых и относительно коротких операций

  • Повторное использование уже созданных потоков вместо создания новых (дорогой процесс)
  • Регулирование скорости создания потоков при наличии большого количества запросов на новые рабочие элементы (я полагаю, что это только в.NET 3.5)

    • Если вы поставите в очередь 100 задач пула потоков, он будет использовать только столько потоков, сколько уже было создано для обслуживания этих запросов (например, 10). Пул потоков будет делать частые проверки (я думаю, каждые 500 мс в 3.5 SP1), и если есть задачи в очереди, он создаст один новый поток. Если ваши задачи выполняются быстро, то количество новых потоков будет небольшим, и повторное использование 10 или около того потоков для коротких задач будет быстрее, чем создание 100 потоков заранее.

    • Если в вашей рабочей нагрузке постоянно поступает большое количество запросов на пул потоков, то пул потоков настроится на вашу рабочую нагрузку, создавая больше потоков в пуле с помощью вышеуказанного процесса, так что для обработки запросов будет доступно большее количество потоков.

    • проверьте здесь для более подробной информации о том, как пул потоков функционирует под капотом

Самостоятельное создание нового потока было бы более уместным, если бы задание длилось относительно долго (возможно, около секунды или двух, но это зависит от конкретной ситуации).

@Krzysztof - потоки пула потоков - это фоновые потоки, которые останавливаются по окончании основного потока. Потоки, созданные вручную, по умолчанию являются приоритетными (будут продолжать работать после завершения основного потока), но их можно установить в фоновом режиме перед вызовом Start для них.

.NET управляемый пул потоков: -

  • Размеры зависят от текущей рабочей нагрузки и доступного оборудования.
  • Содержит рабочие потоки и потоки портов завершения (которые специально используются для обслуживания ввода-вывода)
  • Оптимизирован для большого количества относительно коротких операций

Существуют другие реализации пула потоков, которые могут быть более подходящими для длительных операций.

В частности, используйте пул потоков, чтобы приложение не создавало слишком много потоков. Наиболее важной особенностью пула потоков является рабочая очередь. То есть, как только ваша машина будет достаточно занята, пул потоков будет ставить в очередь запросы, а не сразу создавать больше потоков.

Итак, если вы создадите небольшое, ограниченное количество потоков, создайте их самостоятельно. Если вы не можете заранее определить, сколько потоков может быть создано (например, они созданы в ответ на входящий ввод-вывод), и их работа будет недолгой, используйте пул потоков. Если вы не знаете, сколько их, но их работа будет долгой, на платформе нет ничего, что могло бы вам помочь - но вы могли бы найти альтернативные реализации пула потоков, которые подходят.

Также

new Thread().Start()

порождает поток переднего плана, который не умрет, если вы закроете свою программу. Потоки ThreadPool - это фоновые потоки, которые умирают при закрытии приложения.

Меня интересовало относительное использование ресурсов для них, и я провел тест на моем двухъядерном ноутбуке Intel i5 2012 года, используя сборку релиза.net 4.0 на Windows 8. Пулы потоков потребовали в среднем 0,035 мс, чтобы запустить, где потоки брали в среднем 5,06. Миз. Другими словами, поток в пуле запускается примерно в 300 раз быстрее для большого количества недолговечных потоков. По крайней мере, в тестируемом диапазоне (100-2000) потоков общее время на поток казалось довольно постоянным.

Это код, который был проверен:

    for (int i = 0; i < ThreadCount; i++) {
        Task.Run(() => { });
    }

    for (int i = 0; i < ThreadCount; i++) {
        var t = new Thread(() => { });
        t.Start();
    }

Проверьте здесь для более ранней темы:

Когда я не должен использовать ThreadPool в.Net?

Подводя итог, можно сказать, что Threadpool хорош, если вам нужно порождать много недолговечных потоков, тогда как использование Threads дает вам немного больше контроля.

Если вам нужно много потоков, вы, вероятно, хотите использовать ThreadPool. Они повторно используют потоки, избавляя вас от накладных расходов на создание потоков.

Если вам нужен только один поток, чтобы что-то сделать, поток, вероятно, самый простой.

Основная потребность в потоках adpool заключается в том, чтобы обрабатывать короткие небольшие задачи, которые, как ожидается, завершатся практически мгновенно. Аппаратные обработчики прерываний часто работают в контексте стека, который не подходит для неядерного кода, но аппаратный обработчик прерываний может обнаружить, что обратный вызов завершения пользовательского режима должен быть запущен как можно скорее. Создание нового потока для запуска такой вещи было бы огромным излишним. Наличие нескольких предварительно созданных потоков, которые можно отправить для выполнения обратных вызовов завершения ввода-вывода или других подобных вещей, намного эффективнее.

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

Если нельзя ожидать, что метод завершится в течение 100 мс или около того, когда он начнет выполнение, метод должен выполняться другими способами, отличными от пула основного потока. Если нужно выполнить много задач, которые интенсивно загружают ЦП, но не блокируют, может быть полезно распределить их с помощью пула потоков приложений (по одному на ядро ​​ЦП), который отделен от "основного" пула потоков, поскольку при использовании большее количество потоков, чем ядер, будет контрпродуктивным при выполнении неблокирующих ресурсоемких задач. Однако если выполнение метода займет секунду или дольше и большую часть времени он будет заблокирован, метод, скорее всего, должен выполняться в выделенном потоке и почти наверняка не должен выполняться в потоке основного потока. Если длительная операция должна быть вызвана чем-то вроде обратного вызова ввода / вывода, нужно либо запустить поток для длительной операции перед обратным вызовом и заставить его ждать на мониторе, который пульсирует обратный вызов, либо пусть обратный вызов запускает новый поток, чтобы выполнить операцию, когда обратный вызов завершается, эффективно возвращая свой собственный поток в пул потоков.

Тема:

  1. Создание потока происходит намного медленнее, чем использование пула потоков.
  2. Вы можете изменить приоритет потока.
  3. Максимальное количество потоков в процессе, связанное с ресурсами.
  4. Поток находится на уровне ОС и контролируется ОС.
  5. Использование потока - лучший вариант, когда задача относительно длительная.

Пул потоков:

  1. Запуск потока в пуле потоков намного быстрее, чем непосредственное создание потока.
  2. Вы не можете изменить приоритет выполнения потока на основе пула потоков.
  3. Для каждого процесса существует только один пул потоков.
  4. Пул потоков управляется CLR.
  5. Пул потоков полезен для кратковременной работы.
  6. Количество потоков в пуле потоков зависит от загрузки приложения.
  7. Задачи TPL выполняются на основе пула потоков

Локальное хранилище потоков не является хорошей идеей с пулами потоков. Это дает потокам "идентичность"; не все темы больше не равны. Теперь пулы потоков особенно полезны, если вам просто нужна группа идентичных потоков, готовых выполнять свою работу без дополнительных затрат на создание.

В общем (я никогда не использовал.NET), пул потоков будет использоваться для целей управления ресурсами. Это позволяет ограничениям быть настроенными в вашем программном обеспечении. Это также может быть сделано из соображений производительности, поскольку создание новых потоков может быть дорогостоящим.

Также могут быть системные причины. В Java (опять же, я не знаю, относится ли это к.NET), менеджер потоков может применять переменные, специфичные для каждого потока, когда каждый поток извлекается из пула, и сбрасывать их при возврате (обычный способ передать что-то вроде личность).

Пример ограничения: у меня только 10 дБ соединений, поэтому я бы разрешил только 10 рабочих потоков для доступа к базе данных.

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

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

Просто имейте проблему с формой, использующей поток, чтобы обновить какое-то поле из базы данных для события с измененным положением элемента управления списком (избегайте замораживания). Моему пользователю потребовалось 5 минут, чтобы получить ошибку из базы данных (слишком много связей с Access), потому что он слишком быстро менял позицию списка...

Я знаю, что есть другой способ решения основной проблемы (в том числе не используя доступ), но пул - хорошее начало.

Другие вопросы по тегам