Оптимальное количество потоков на ядро - PullRequest
256 голосов
/ 12 ноября 2009

Допустим, у меня есть 4-ядерный процессор, и я хочу запустить какой-то процесс за минимальное количество времени. Этот процесс идеально распараллеливается, поэтому я могу запускать его в бесконечном количестве потоков, и каждый поток занимает одинаковое количество времени.

Поскольку у меня 4 ядра, я не ожидаю ускорения, запустив больше потоков, чем ядер, поскольку одно ядро ​​способно запустить только один поток в данный момент. Я не очень разбираюсь в оборудовании, так что это только предположение.

Есть ли преимущество запуска параллельного процесса на большем количестве потоков, чем на ядрах? Другими словами, завершится ли мой процесс быстрее, медленнее или примерно за то же время, если я запустю его с использованием 4000 потоков, а не 4 потоков?

Ответы [ 13 ]

235 голосов
/ 12 ноября 2009

Если ваши потоки не выполняют ввод-вывод, синхронизацию и т. Д., И больше ничего не работает, 1 поток на ядро ​​обеспечит вам наилучшую производительность. Однако это, скорее всего, не так. Добавление большего количества потоков обычно помогает, но через некоторое время они вызывают некоторое снижение производительности.

Не так давно я проводил тестирование производительности на двухъядерном компьютере с приложением ASP.NET в Mono под довольно приличной нагрузкой. Мы поиграли с минимальным и максимальным количеством потоков и в итоге обнаружили, что для этого конкретного приложения в этой конкретной конфигурации лучшая пропускная способность была где-то между 36 и 40 потоками. Все, что находится за пределами этих границ, работает хуже. Урок выучен? На вашем месте я бы проверил с другим количеством потоков, пока вы не найдете правильный номер для вашего приложения.

Одно могу сказать наверняка: потоки 4k займут больше времени. Это много переключений контекста.

121 голосов
/ 20 мая 2012

Я согласен с ответом @ Gonzalo. У меня есть процесс, который не выполняет ввод / вывод, и вот что я нашел:

enter image description here

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

Машина 1.86 - это MacBook Air с твердотельным накопителем. Другой Mac - iMac с обычным жестким диском (я думаю, что это 7200 оборотов в минуту). Машина для Windows также имеет жесткий диск 7200 об / мин.

В этом тесте оптимальное количество было равно количеству ядер в машине.

46 голосов
/ 27 декабря 2012

Я знаю, что этот вопрос довольно старый, но с 2009 года ситуация изменилась.

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

В процессорах Intel количество потоков определяется гиперпоточностью, равной всего 2 (если доступно). Но Hyperthreading сокращает ваше время выполнения в два раза, даже если не используется 2 потока! (то есть 1 конвейер, совместно используемый двумя процессами - это хорошо, когда у вас больше процессов, но не так хорошо в противном случае. Чем больше ядер, тем лучше!)

На других процессорах у вас может быть 2, 4 или даже 8 потоков. Так что если у вас есть 8 ядер, каждое из которых поддерживает 8 потоков, у вас может быть 64 параллельно работающих процесса без переключения контекста.

«Без переключения контекста», очевидно, неверно, если вы работаете со стандартной операционной системой, которая будет выполнять переключение контекста для всех видов вещей вне вашего контроля. Но это главная идея. Некоторые операционные системы позволяют вам распределять процессоры так, чтобы только ваше приложение имело доступ / использование указанного процессора!

Исходя из моего собственного опыта, если у вас много операций ввода-вывода, хорошо использовать несколько потоков. Если у вас очень тяжелая работа с памятью (чтение источника 1, чтение источника 2, быстрые вычисления, запись), тогда наличие большего количества потоков не поможет. Опять же, это зависит от того, сколько данных вы читаете / пишете одновременно (то есть, если вы используете SSE 4.2 и читаете 256-битные значения, это останавливает все потоки на их шаге ... другими словами, 1 поток, вероятно, намного проще реализовать и вероятно, почти так же быстро, если не на самом деле быстрее. Это будет зависеть от вашей архитектуры процессов и памяти, некоторые продвинутые серверы управляют отдельными диапазонами памяти для отдельных ядер, поэтому отдельные потоки будут работать быстрее при условии, что ваши данные правильно хранятся ... поэтому на некоторых В архитектурах 4 процесса будут выполняться быстрее, чем 1 процесс с 4 потоками.)

23 голосов
/ 12 ноября 2009

Фактическая производительность будет зависеть от того, сколько добровольных выходов будет делать каждый поток. Например, если потоки вообще не выполняют никаких операций ввода-вывода и не используют системные службы (т. Е. Они на 100% связаны с процессором), то оптимальным является 1 поток на ядро. Если потоки делают что-то, что требует ожидания, вам придется поэкспериментировать, чтобы определить оптимальное количество потоков. 4000 потоков могут привести к значительным накладным расходам на планирование, так что это, вероятно, также не оптимально.

18 голосов
/ 05 августа 2014

Ответ зависит от сложности алгоритмов, используемых в программе. Я придумал метод вычисления оптимального числа потоков, выполнив два измерения времени обработки Tn и Tm для двух произвольных чисел потоков: «n» и «m». Для линейных алгоритмов оптимальным числом потоков будет N = sqrt ((m n (Tm * (n-1) - Tn * (m-1))) / (n Tn- м тм)).

Пожалуйста, прочитайте мою статью о вычислениях оптимального числа для различных алгоритмов: pavelkazenin.wordpress.com

7 голосов
/ 17 марта 2017

Я думал, что добавлю еще одну перспективу здесь. Ответ зависит от того, предполагает ли вопрос слабое или сильное масштабирование.

Из Википедия :

Слабое масштабирование: как время решения зависит от количества процессоров для фиксированного размера проблемы на процессор.

Сильное масштабирование: как время решения зависит от количества процессоров для фиксированного общего размера проблемы.

Если вопрос предполагает слабое масштабирование, то ответа @ Gonzalo достаточно. Однако, если вопрос предполагает сильное масштабирование, есть что добавить. При строгом масштабировании вы предполагаете фиксированный размер рабочей нагрузки, поэтому, если вы увеличиваете количество потоков, размер данных, с которыми должен работать каждый поток, уменьшается. На современных процессорах доступ к памяти дорогостоящий и предпочтительнее поддерживать локальность, сохраняя данные в кэш-памяти. Следовательно, вероятное оптимальное количество потоков может быть найдено , когда набор данных каждого потока помещается в кэш каждого ядра (я не буду вдаваться в детали обсуждения того, является ли это L1 / L2 / L3 кеша (ов) системы).

Это верно даже тогда, когда количество потоков превышает количество ядер. Например, предположим, что в программе есть 8 произвольных единиц (или AU) работы, которая будет выполняться на 4-ядерном компьютере.

Случай 1: выполняется с четырьмя потоками, где каждый поток должен заполнить 2AU. Каждый поток завершается за 10 секунд ( с большим количеством пропусков кэша ). С четырьмя ядрами общее время составит 10 с (10 с * 4 потока / 4 ядра).

Случай 2: выполняется с восемью потоками, где каждый поток должен заполнить 1 AU. Каждый поток занимает всего 2 с (вместо 5 с из-за уменьшенного количества пропусков кэша ). С восемью ядрами общее время составит 4 с (2 с * 8 потоков / 4 ядра).

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

7 голосов
/ 12 ноября 2009

4000 потоков за один раз довольно высоки.

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

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

6 голосов
/ 12 ноября 2009

Benchmark.

Я бы начал увеличивать количество потоков для приложения, начиная с 1, а затем переходя к чему-то вроде 100, выполняя три-пять испытаний для каждого числа потоков и составляя себе график зависимости скорости работы от количество потоков.

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

Ты не сможешь знать, пока не проверишь.

3 голосов
/ 23 октября 2017

Вы можете узнать, сколько потоков вы можете запустить на своей машине, запустив команду htop или ps, которая возвращает номер процесса на вашей машине.

Вы можете использовать справочную страницу о команде 'ps'.

man ps

Если вы хотите рассчитать количество всех пользователей процесса, вы можете использовать одну из следующих команд:

  1. ps -aux| wc -l
  2. ps -eLf | wc -l

Расчет номера пользовательского процесса:

  1. ps --User root | wc -l

Также вы можете использовать "htop" [Ссылка] :

Установка в Ubuntu или Debian:

sudo apt-get install htop

Установка на Redhat или CentOS:

yum install htop
dnf install htop      [On Fedora 22+ releases]

Если вы хотите скомпилировать htop из исходного кода, вы найдете его здесь .

2 голосов
/ 13 февраля 2012

Один пример большого количества потоков («пул потоков») против одного на ядро ​​- это пример реализации веб-сервера в Linux или в Windows.

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

В Windows сервер будет реализован с использованием портов завершения ввода-вывода - IOCP - что сделает событие приложения управляемым: при завершении ввода-вывода ОС запускает резервный поток для его обработки. Когда обработка завершена (обычно с другой операцией ввода-вывода, как в паре запрос-ответ), поток возвращается к порту (очереди) IOCP, чтобы дождаться следующего завершения.

Если ввод-вывод не завершен, обработка не выполняется и поток не запускается.

Действительно, Microsoft рекомендует не более одного потока на ядро ​​в реализациях IOCP. Любой ввод / вывод может быть присоединен к механизму IOCP. При необходимости МОК могут быть размещены приложением.

...