Оптимальное количество потоков на ядро

281

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

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

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

Джульетта
источник

Ответы:

254

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

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

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

Гонсало
источник
21
Я думаю, что ответ Гонсало хороший. Я бы просто добавил, что вы должны экспериментировать и измерять. Ваша программа будет отличаться от его или моей, или чьей-либо другой, и только измерения поведения вашей собственной программы ответят на ваши вопросы должным образом. Выполнение параллельных (или параллельных) программ не является областью, в которой можно сделать хорошие выводы из одних только первых принципов.
Высокая производительность Марк
5
+1, + answer: меня удивляет, что наличие гораздо большего количества потоков, чем ядер, приводит к лучшей производительности, хотя и имеет смысл, если большее количество потоков означает большую долю времени по сравнению с конкурирующими потоками. Было бы неплохо, чтобы мое приложение могло обнаруживать различия в производительности и автоматически настраиваться на оптимальное количество потоков.
Джульетта
12
Это не должно удивлять вас в реальном сценарии. Потоки блокируют ожидание ресурсов ввода-вывода, таких как доступ к диску, сеть и т. Д. А также ожидают, когда ресурсы, не относящиеся к вводу-выводу, такие как другие потоки, завершат использование общих переменных. Чего вы действительно хотите добиться, так это минимального количества потоков, чтобы всегда мог работать хотя бы один поток на ядро.
Patros
4
1 нить на ядро ​​не является оптимальной. Это должно быть немного больше, предпочтительно вдвое больше, так как это позволит другому потоку работать, если поток временно заблокирован. Даже если только на память. Это более важно, если у вас есть системы (P4, I7, Sun Rock и т. Д.), Которые поддерживают SMT / HT)
Марко ван де Воорт,
1
Отсюда и «это, скорее всего, не тот случай» в моем ответе. Поиск правильного числа зависит от приложения и архитектуры, на которой оно работает.
Гонсало
129

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

введите описание изображения здесь

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

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

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

Motasim
источник
14
+1 за график. Ясно, что лучше всего 1 поток на ядро, но интересно, что четырехъядерная система, похоже, не имеет более высоких номеров потоков (в любом случае, <100), как остальные.
Джим Гаррисон
46
-1 за график! Гладкие кривые через целочисленные x-координаты? Дикий прыжок с 1 2 3 до 10 20 30 до 50 100? И Y-координаты, которые кратны 10 плюс 2 для хорошей меры. Это делает Excel, не так ли?
Spacedman
5
@ Spacedman Да, это так. ИМХО гладкие кривые выглядят намного лучше. : D
Motasim
22
@PascalvKooten, проблема не в том, что это выглядит красиво, это обманчиво на первый взгляд. Прежде всего, ось Y начинается с 42, преувеличивая кажущуюся разницу между тестируемыми машинами. Во-вторых, странная прогрессия значений по оси X предполагает, что «затраченное время» не масштабируется линейно с «числом потоков», это особенно верно для синей линии. Я думаю, что проблема, с которой сталкиваются другие (включая меня), состоит в том, что они искажают данные.
pauluss86
13
@Spacedman Критика на графике - самая нелепая вещь, с которой я столкнулся за последние 24 часа. График помогает. Много. Период. Могло ли это быть сделано лучше? Всем всеравно. Гладкая кривая вместо дискретной? Это твоя проблема ???? Я предполагаю, что все вы никогда бы не включили такой график в свой ответ, потому что у вас нет дополнительного времени / энергии, чтобы он выглядел хорошо. Это моя точка зрения.
Tyrex
50

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

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

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

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

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

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

Алексис Уилке
источник
4
Возможно, есть и другие, но я знаю, что это процессор POWER от IBM. У них были системы с 4 или 8 потоками на процессоры. Теперь они могут запускать больше ядер, поэтому вместо них они предлагают по 2 потока на каждое ядро ​​...
Алексис Уилк
Это старый, но большинство Intel i5, i7 имеют многопоточные процессоры, как, например, процессоры i7 обычно имеют 4 ядра, но 8 потоков.
Edgar.A
4
Процессоры не имеют потоков. У них есть физические и логические ядра. При гиперпоточности одно физическое ядро ​​функционирует как два логических ядра. У меня была технология, которая настаивала на том, что процессоры с потоками - это настоящая вещь, поэтому я нарисовал на доске изображение процессора с торчащим из него шпинделем потока.
@TechnikEmpire Посмотрите на этот сайт intel.com/content/www/us/en/processors/core/… , может быть, тогда вы сможете связаться с Intel и нарисовать темы.
g7k
24

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

Джим гаррисон
источник
21

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

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

pkazen
источник
4
Почему это понижено? Извините, но это лучший ответ на этот вопрос. Гонсало обращается к жирной части вопроса, а pkazen обращается к названию. Оба ответа очень полезны, но ответ pkazen уместен, потому что у нас есть систематический метод для аппроксимации количества потоков. Он даже дает формулу для линейных алгоритмов.
tobiak777
1
Я не понизил голос, но если бы я это сделал, то это было бы на основе того, что нет реального объяснения того, почему или как оптимальное количество потоков может быть связано со сложностью алгоритма, за исключением чтения всей связанной статьи, которая это долго читать (из-за сложности статьи). Кроме того, некоторые аспекты статьи мне не ясны, главное, как экспериментальные результаты подтверждают теорию.
Кодирование
Кроме того, я считаю, что этот расчет предполагает, что у вас бесконечное количество процессорных ядер. Хотя это определенно ценная информация, вопрос касается реальных машин с небольшим количеством ядер.
Навит
9

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

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

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

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

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

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

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

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

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

someneat
источник
7

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

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

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

Earlz
источник
7

Benchmark.

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

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

Вы не можете знать, пока не будете тестировать.

MMR
источник
3

Вы узнаете, сколько потоков вы можете запустить на своем компьютере, запустив команду 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

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

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

patros
источник
Это зависит от того, хотите ли вы, чтобы пользовательские фоновые процессы работали как дерьмо во время работы вашего приложения. В этом отношении вы можете просто установить приоритет в реальном времени для каждого потока и получить максимальную мощность. Но пользователям нравится многозадачность.
Эрлз
2
Ну, мы имеем дело с волшебным идеально распараллеливаемым приложением. Если бы я когда-либо создавал такую ​​вещь, я чувствовал бы право загружать процессор столько, сколько я хочу.
Patros
2

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

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

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

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

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

Олоф Форшелл
источник
Я не знаю, о каком Linux вы говорите, но мои блоки пока не установится соединение. Я предлагаю вам прочитать несколько вещей о select () и FD_SET () и аналогичных функциях / макросах.
Алексис Уилке
Итак, нет асинхронной формы, которая немедленно возвращается?
Олоф Форшелл
На странице timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval structure are zero, then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.
справки
0

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

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

Anycorn
источник
0

Надеюсь, что это имеет смысл. Проверьте использование ЦП и памяти и установите пороговое значение. Если пороговое значение пересечено, не позволяйте создавать новый поток, иначе разрешите ...

М. Гопал
источник