Оптимальное количество потоков на ядро
допустим, у меня есть 4-ядерный процессор, и я хочу запустить какой-то процесс за минимальное количество времени. Процесс идеально распараллеливается, поэтому я могу запускать его куски на бесконечном количестве потоков, и каждый поток занимает одинаковое количество времени.
поскольку у меня есть 4 ядра, я не ожидаю ускорения, запустив больше потоков, чем ядер, поскольку одно ядро способно запускать только один поток в данный момент. Я не очень разбираюсь в оборудовании, так что это всего лишь догадка.
есть ли польза от запуска распараллеливаемого процесса на большем количестве потоков, чем ядер? Другими словами, Будет ли мой процесс заканчиваться быстрее, медленнее или примерно за то же время, если я запускаю его с использованием 4000 потоков, а не 4 потоков?
13 ответов:
Если ваши потоки не выполняют ввод-вывод, синхронизацию и т. д., и больше ничего не работает, 1 поток на ядро даст вам лучшую производительность. Однако это, скорее всего, не так. Добавление большего количества потоков обычно помогает, Но через некоторое время они вызывают некоторое снижение производительности.
Не так давно я проводил тестирование производительности на двух четырехъядерной машине под управлением ASP.NET приложение на моно под довольно приличной нагрузкой. Мы играли с минимальным и максимальным количеством потоков и в конце концов мы обнаружили, что для этого конкретного приложения в этой конкретной конфигурации лучшая пропускная способность была где-то между 36 и 40 потоками. Все, что находилось за пределами этих границ, работало хуже. Урок усвоен? Если бы я был на вашем месте, я бы тестировал с разным количеством потоков, пока вы не найдете правильный номер для своего приложения.
одно можно сказать наверняка: 4K потоки займет больше времени. Это много переключений контекста.
Я согласен с ответом @ Gonzalo. У меня есть процесс, который не делает ввода-вывода, и вот что я нашел:
обратите внимание, что все потоки работают на одном массиве, но разные диапазоны (два потока не имеют доступа к одному и тому же индексу), поэтому результаты могут отличаться, если они работали на разных массивах.
машина 1.86-это macbook air с SSD. Другой mac-это iMac с обычным HDD (я думаю, что это 7200 об / мин). Машина windows также имеет 7200 об / мин ВИНЧЕСТЕР.
в этом тесте оптимальное число было равно числу ядер в машине.
Я знаю, что этот вопрос довольно старый, но все изменилось с 2009 года.
теперь нужно учитывать две вещи: Количество ядер и количество потоков, которые могут работать в каждом ядре.
с процессорами Intel количество потоков определяется гиперпоточностью, которая составляет всего 2 (при наличии). Но Hyperthreading сокращает время выполнения на два, даже если не использует 2 потока! (т. е. трубопровод 1 разделен между двумя процессами-это хорошо когда у вас больше процессов, не так хорошо иначе. Больше ядер определенно лучше!)
на других процессорах вы можете иметь 2, 4 или даже 8 потоков. Поэтому, если у вас есть 8 ядер, каждое из которых поддерживает 8 потоков, вы можете иметь 64 процесса, работающих параллельно без переключения контекста.
"нет переключения контекста", очевидно, не верно, если вы работаете со стандартной операционной системой, которая будет делать переключение контекста для всех видов других вещей из-под вашего контроля. Но это основная идея. Некоторые ОС позволяют выделять процессоры, так что только ваше приложение имеет доступ / использование указанного процессора!
из собственного опыта, если у вас много операций ввода-вывода, несколько потоков-это хорошо. Если у вас очень тяжелая интенсивная работа с памятью (источник чтения 1, Источник чтения 2, быстрые вычисления, запись), то наличие большего количества потоков не помогает. Опять же, это зависит от того, сколько данных Вы читаете/записываете одновременно (т. е. если вы используете SSE 4.2 и читаете значения 256 бит, это останавливает все потоки в их шаг... другими словами, 1 поток, вероятно, намного проще реализовать и, вероятно, почти так же быстро, если не на самом деле быстрее. Это будет зависеть от вашего процесса и архитектуры памяти, некоторые продвинутые серверы управляют отдельными диапазонами памяти для отдельных ядер, поэтому отдельные потоки будут быстрее, если ваши данные правильно поданы... именно поэтому на некоторых архитектурах 4 процесса будут выполняться быстрее, чем 1 процесс с 4 потоками.)
фактическая производительность будет зависеть от того, сколько добровольной отдачи будет делать каждый поток. Например, если потоки вообще не выполняют ввод-вывод и не используют системные службы (т. е. они связаны с процессором на 100%), то 1 поток на ядро является оптимальным. Если потоки делают все, что требует ожидания, то вам придется поэкспериментировать, чтобы определить оптимальное количество потоков. 4000 потоков потребуют значительных затрат на планирование, так что это, вероятно, тоже не оптимально.
ответ зависит от сложности алгоритмов, используемых в программе. Я придумал метод расчета оптимального количества потоков, сделав два измерения времени обработки Tn и Tm для двух произвольных чисел потоков ‘n’ и ‘m’. Для линейных алгоритмов оптимальным числом потоков будет N = sqrt ((mn(Tm*(n-1)-Tn*(m-1)))/(nTn-mTm) ) .
пожалуйста, прочитайте мою статью о расчетах оптимального числа для различные алгоритмы: pavelkazenin.wordpress.com
4000 потоков в одно время довольно высоко.
ответ да и нет. Если вы делаете много блокирующих операций ввода-вывода в каждом потоке, то да, вы можете показать значительное ускорение, возможно, до 3 или 4 потоков на логическое ядро.
Если вы не делаете много блокирующих вещей, однако, то дополнительные накладные расходы с резьбой будет просто сделать его медленнее. Поэтому используйте профилировщик и посмотрите, где узкие места находятся в каждой возможной параллельной части. Если вы делаете тяжелый вычисления, то более 1 потока на процессор не поможет. Если вы делаете много передачи памяти, это тоже не поможет. Если вы делаете много ввода / вывода, хотя, например, для доступа к диску или доступу в интернет, то да несколько потоков поможет до определенной степени, или по крайней мере сделать приложение более отзывчивым.
Я думал, что добавлю еще одну перспективу здесь. Ответ зависит от того, предполагает ли вопрос слабое масштабирование или сильное масштабирование.
с Википедия:
слабое масштабирование: как время решения зависит от количества процессоров для фиксированного размера проблемы на процессор.
сильное масштабирование: как время решения зависит от количества процессоров для фиксированного общего размера проблемы.
Если вопрос предполагает слабое масштабирование, тогда достаточно ответа @ Gonzalo. Однако если вопрос предполагает сильное масштабирование, есть что-то еще, чтобы добавить. При сильном масштабировании вы предполагаете фиксированный размер рабочей нагрузки, поэтому при увеличении количества потоков размер данных, с которыми должен работать каждый поток, уменьшается. На современных процессорах доступ к памяти стоит дорого и было бы предпочтительнее поддерживать локальность, сохраняя данные в кэшах. Поэтому, вероятно, оптимальное количество потоков может быть нашел когда набор данных каждого потока помещается в кэш каждого ядра (Я не буду вдаваться в детали обсуждения, является ли это L1/L2/L3 кэш (ы) системы).
Это справедливо даже тогда, когда количество потоков превысит количество ядер. Например, предположим, что в программе есть 8 произвольных единиц (или AU) работы, которые будут выполняться на 4-ядерном компьютере.
Пример 1: запуск с четырьмя потоками, где каждый поток должен полное 2AU. Каждый поток занимает 10 секунд для завершения (с большим количеством промахов кэша). С четырьмя ядрами общее количество времени будет 10С (10С * 4 потока / 4 ядра).
Пример 2: запуск с восемью потоками, где каждый поток должен завершить 1AU. Каждый поток занимает только 2s (вместо 5s из-за уменьшено количество промахов кэша). С восемью ядрами общее количество времени составит 4s (2S * 8 потоков / 4 начинка.)
я упростил проблему и проигнорировал накладные расходы, упомянутые в других ответах (например, переключатели контекста), но надеюсь, что вы поймете, что может быть полезно иметь больше потоков, чем доступное количество ядер, в зависимости от размера данных, с которыми вы имеете дело.
эталоном.
Я бы начал наращивать количество потоков для приложения, начиная с 1, а затем перейти к чему-то вроде 100, запустить три-пять проб для каждого количества потоков и построить себе график скорости работы против количества потоков.
вы должны, чтобы случай с четырьмя потоками был оптимальным, с небольшим повышением времени выполнения после этого, но, возможно, нет. Возможно, ваше приложение ограничено пропускной способностью, т. е. набор данных, который вы загружаете в память, огромен, вы получаете много промахов кэша и т. д., Так что 2 потока являются оптимальными.
вы не можете знать, пока вы не проверить.
вы найдете, сколько потоков вы можете запустить на вашем компьютере, запустив команду htop или ps, которая возвращает количество процессов на вашем компьютере.
вы можете использовать man-страницу о команде "ps".
man psесли вы хотите рассчитать количество всех пользователей процесса, вы можете использовать одну из следующих команд:
ps -aux| wc -lps -eLf | wc -lвычисление количества пользователей процесс:
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 из исходного кода, вы найдете его здесь.
идеальным является 1 поток на ядро, пока ни один из потоков не будет блокировать.
один случай, когда это может быть неверно: есть другие потоки, работающие на ядре, и в этом случае больше потоков может дать вашей программе больший кусок времени выполнения.
одним из примеров большого количества потоков ("пул потоков") против одного на ядро является реализация веб-сервера в Linux или Windows.
поскольку сокеты опрашиваются в Linux, множество потоков может увеличить вероятность того, что один из них опросит правильный сокет в нужное время, но общая стоимость обработки будет очень высокой.
в Windows сервер будет реализован с использованием портов завершения ввода-вывода-IOCPs - что сделает приложение управляемым событием: если ввод-вывод завершает ОС запускает резервный поток для его обработки. Когда обработка завершена (обычно с другой операцией ввода-вывода, Как в паре запрос-ответ), поток возвращается к порту IOCP (очереди), чтобы дождаться следующего завершения.
Если ввод-вывод не завершен, обработка не выполняется и поток не запускается.
действительно, Microsoft рекомендует не более одного потока на ядро в реализациях IOCP. Любой ввод/вывод может быть присоединен к механизму МОК. МОК может также будет размещена заявка, если это необходимо.
говоря с точки зрения вычислений и памяти (научные вычисления) 4000 потоков заставят приложение работать очень медленно. Частью проблемы является очень высокие накладные расходы на переключение контекста и, скорее всего, очень плохая локальность памяти.
но это также зависит от вашей архитектуры. Откуда я слышал, что процессоры Niagara, как предполагается, могут обрабатывать несколько потоков на одном ядре, используя какую-то передовую технику конвейерной обработки. Однако у меня нет опыта с этими процессорами.
надеюсь, что это имеет смысл, Проверьте загрузку процессора и памяти и установите некоторое пороговое значение. Если пороговое значение пересекается,не позволяйте создавать новый поток, иначе разрешить...

Comments