Почему использование большего количества потоков делает это медленнее, чем использование меньшего количества потоков

30

Попытался запустить программу X, используя 8 потоков, и это было закончено через n минут .
Пытался запустить ту же программу, используя 50 потоков, и это было закончено за n * 10 минут .

Почему это происходит и как я могу получить оптимальное количество потоков, которые я могу использовать?

PoGibas
источник

Ответы:

33

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

Является ли процесс / поток

  • Процессор привязан (требуется много ресурсов процессора)
  • Ограничение памяти (требуется много ресурсов оперативной памяти)
  • Привязка ввода / вывода (ресурсы сети и / или жесткого диска)

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

Вы можете использовать ntopи iostat, и vmstatдля диагностики того, что происходит.

SLM
источник
8
Аппаратное обеспечение тоже имеет значение. Физическое, виртуальное, количество ядер, тип ядра, кэш-память L1 / L2 / L3 и т. Д.
EightBitTony
46

"Почему это происходит?" вроде легко ответить. Представьте, что у вас есть коридор, в котором вы можете разместить четырех человек рядом друг с другом. Вы хотите переместить весь мусор с одного конца, с другого конца. Самое эффективное количество людей - 4.

Если у вас 1-3 человека, вам не хватает пространства в коридоре. Если у вас 5 или более человек, то, по крайней мере, один из этих людей все время застревает в очереди за другим человеком. Добавление все большего количества людей просто забивает коридор, это не ускоряет активность.

Таким образом, вы хотите, чтобы у вас было столько людей, сколько вы можете вместить без очереди. Почему у вас есть очереди (или узкие места) зависит от вопросов в ответе slm.

EightBitTony
источник
1
Ваш пример вводит в заблуждение. Было бы лучше сказать что-то вроде: «У вас есть коридор, в котором вы можете разместить четырех человек внизу, и он используется вами и другими людьми для различных задач. Есть судья, который решает, кто может пройти по коридору. Тогда самое эффективное число людей больше 4 и меньше некоторого числа, где ваши люди начинают стоять в очереди [в значительной степени зависит от контекста]. " Обычно наличие некоторых потоков больше, чем число процессоров, работает лучше, чем использование ровно 4 потоков. Если вы используете процессор только один, то 4это лучший номер.
Бакуриу
7
Отличный пример +1. Bakuriu, это пример, который иллюстрирует проблему ограниченного общего ресурса. Это объясняет проблему, а не как найти оптимальное количество потоков.
Bananguin
1
Также было бы полезно иметь в виду, что у потоков все еще есть свой собственный тип переключения контекста, который продолжается. Увеличение количества потоков не увеличивает производительность (как вы указали), но также снижает нагрузку на процессор, давая ядру больше работы. По сути, снижается отдача от многопоточности, что приводит к чрезмерному снижению производительности.
Братчли
9
Каждая проблема может быть описана на многих уровнях сложности. Я предложил приближение к проблеме, которая, по моему мнению, полезна для объяснения основ. Конечно, это может быть более изощренным и более подробным, но чем более подробным вы это сделаете, тем менее полезным оно будет в качестве введения в проблему.
EightBitTony
Я бы добавил, что вместо того, чтобы тратить много времени на вычисление оптимального количества потоков, просто закодируйте его, чтобы его можно было легко изменить. Любое крупное слияние, подобное этому, потребует многочисленных тестовых прогонов (большинство с небольшими подмножествами ваших данных) для совершенствования Увеличивайте количество потоков до тех пор, пока не увидите значительное падение производительности или неприемлемое влияние на активность других систем.
DocSalvager
20

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

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

frostschutz
источник
Это должен быть общий ответ, учитывая количество информации, доступной в вопросе. нам не нужен полномасштабный тезис и философия, как и другие ответы
Аллахжане
9

Как другие отмечали, ( ОДС ответ , EightBitTony ответ ) это сложный вопрос , и тем более, так как вы не описать то , что вы thred делать и как они это делают.

Но окончательное добавление большего количества потоков может ухудшить ситуацию.

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

Суть закона Амдаля заключается в том, что в любой программе (в любом алгоритме) всегда есть процент, который не может быть запущен параллельно ( последовательная часть ), и есть другой процент, который может быть запущен параллельно ( параллельная часть ) [Очевидно, эти две части составляют до 100%].

Эта часть может быть выражена в процентах от времени выполнения. Например, 25% времени может быть потрачено на строго последовательные операции, а оставшиеся 75% времени уходит на операции, которые могут выполняться параллельно.

Изображение из Википедии (Изображение из Википедии )

Закон Амдаля предсказывает, что для каждой заданной параллельной части (например, 75%) программы вы можете ускорить выполнение только до сих пор (например, не более 4 раз), даже если для выполнения работы вы используете все больше и больше процессоров.

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

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

Этот теоретический прогноз (о времени ЦП) не учитывает практические узкие места как

  1. Ограниченная скорость ввода / вывода («скорость» жесткого диска и сети)
  2. Пределы памяти
  3. другие

это легко может быть ограничивающим фактором в практическом применении.

DavAlPi
источник
Это должен быть выбран ответ.
Эонил
6

Виновником здесь должно быть «ПЕРЕКЛЮЧЕНИЕ КОНТЕКСТА». Это процесс сохранения состояния текущего потока, чтобы начать выполнение другого потока. Если несколько потоков имеют одинаковый приоритет, их необходимо переключать до завершения выполнения.

В вашем случае, когда имеется 50 потоков, происходит много переключений контекста по сравнению с просто выполнением 10 потоков.

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

X-Treme
источник
Поскольку мы не знаем, что это за нити, это предположение. Да, переключение контекста добавляет издержки, но если потоки выполняют какой-то анализ данных, проблема может заключаться в проблемах с кешем (т. Е. Невозможностью использовать кеш, потому что каждый раз, когда вы переключаете потоки, вы должны очищать его).
EightBitTony
Переключение контекста потока само по себе , если мы не имеем дело с огромным количеством переключений контекста, скорее всего, не окажет влияния на производительность на порядок. 50 потоков - это высокий уровень, но не экстремальный (на моем компьютере сейчас ps ax | wc -l225 процессов, и он ни в коем случае не сильно загружен). Я склонен согласиться с предположением @ EightBitTony; аннулирование кеша, вероятно, является более серьезной проблемой, потому что каждый раз, когда вы очищаете кеш, процессор должен ждать эоны для кода и данных из оперативной памяти.
CVn
3

Чтобы исправить метафору EightBitTony:

"Почему это происходит?" вроде легко ответить. Представьте, что у вас есть два бассейна, один полный и один пустой. Вы хотите переместить всю воду от одного к другому, и у вас есть 4 ведра . Самое эффективное количество людей - 4.

Если у вас 1-3 человека, то вам не хватает нескольких ведер . Если у вас 5 или более человек, то хотя бы один из них застрял в ожидании ведра . Добавление все большего количества людей ... не ускоряет деятельность.

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

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

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

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

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


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

На самом деле этот сценарий очень похож на стандартное описание взаимосвязи между задержкой и размером окна в сети TCP, поэтому он у меня появился.

Бесполезный
источник
Это не метафора, это приближение, предназначенное для объяснения системы людям таким образом, чтобы они могли легко ее визуализировать. Таким образом, он всегда будет «мусорным» для людей, которые знают следующий уровень детализации, но не понимают, что их уровень детализации на самом деле не является необходимым для начинающих. Никто не изучает физику элементарных частиц, начиная с уровня PhD. Все вещи, представленные ранее, являются приближением, они постепенно ведут вас к этому, совершенствуя его по мере продвижения. Это не «неправильно», это просто не полная картина.
EightBitTony
Никто не смущен тем, какую фигуру речи вы использовали, и это неплохая аналогия. Каждая аналогия имеет некоторый предел, за которым она расходится с тем, что она должна описывать, и перестает быть полезной. Я упомянул об этом только потому, что оригинал так сильно напомнил мне другой сценарий, и потому что я не думаю, что эта версия более сложна для (надеюсь) улучшения предсказуемости.
бесполезно
0

Это довольно просто и понятно. Имея больше потоков, чем поддерживает ваш процессор, вы фактически сериализуетесь, а не распараллеливаете. Чем больше у вас потоков, тем медленнее будет ваша система. Ваши результаты на самом деле являются доказательством этого явления.

Бруно Табоада
источник