Ответ 1
Утверждения не верны как общее утверждение. То есть, иногда они истинны (или правдивы), а иногда они явно ложны.
Пару вещей бесспорная истина:
-
Больше потоков означает больше использования памяти. Каждый поток требует стека потока. Для недавних виртуальных машин HotSpot минимальный размер стека потоков составляет 64 КБ, а по умолчанию он может достигать 1 МБ. Это может быть значительным. Кроме того, любой живой поток может владеть или совместно использовать объекты в куче, независимо от того, работает ли он в данный момент. Поэтому разумно ожидать, что большее количество потоков означает больший рабочий объем памяти.
-
JVM не может иметь больше работающих потоков, чем есть ядра (или ядра с гиперпоточностью или что-то еще) на исполнительном оборудовании. Автомобиль не будет работать без двигателя, а поток не будет работать без сердечника.
Помимо этого, вещи становятся менее четкими. "Проблема" в том, что живой поток может находиться в разных "состояниях". Например:
- Прямой поток может быть запущен; т.е. активно выполняющие инструкции.
- Прямой поток может быть запущен; то есть ожидание ядра, чтобы оно могло быть запущено.
- Прямой поток может быть синхронизирован; т.е. ожидание сигнала от другого потока или ожидание снятия блокировки.
- Прямой поток может ожидать внешнего события; например, ожидание ответа какого-либо внешнего сервера/службы на запрос.
Эвристика "один поток на ядро" предполагает, что потоки либо работают, либо работают (в соответствии с вышеизложенным). Но для многих многопоточных приложений эвристика ошибочна... потому что она не учитывает потоки в других состояниях.
Теперь очевидно, что "слишком много" потоков может привести к значительному снижению производительности, просто используя слишком много памяти. (Представьте, что у вас есть 4 ГБ физической памяти, и вы создаете 8 000 потоков со стеками 1 МБ. Это рецепт для перебора виртуальной памяти.)
Но как насчет других вещей? Может ли слишком много потоков вызвать чрезмерное переключение контекста?
Я так не думаю. Если у вас много потоков, и использование этих потоков вашим приложением может привести к чрезмерному переключению контекста, что отрицательно сказывается на производительности. Тем не менее, я утверждаю, что основной причиной переключения контекста является не фактическое количество потоков. Корень проблем с производительностью более вероятно, что приложение:
- синхронизация особенно расточительно; например, используя
Object.notifyAll()
когдаObject.notify()
будет лучше, ИЛИ - синхронизация в очень сложной структуре данных, ИЛИ
- выполняется слишком много синхронизации относительно объема полезной работы, которую выполняет каждый поток, ИЛИ
- пытаясь сделать слишком много ввода-вывода параллельно.
(В последнем случае узким местом, скорее всего, будет система ввода-вывода, а не переключение контекста... если только ввод-вывод не является IPC со службами/программами на одной машине.)
Другой момент заключается в том, что при отсутствии вышеупомянутых смешанных факторов наличие большего количества потоков не приведет к увеличению переключений контекста. Если ваше приложение имеет N исполняемых потоков, конкурирующих за M процессоров, и потоки являются чисто вычислительными и свободными от конкуренции, то планировщик потоков операционной системы попытается сократить временной интервал между ними. Но длина временного среза, вероятно, будет измеряться в десятых долях секунды (или более), поэтому издержки переключения контекста незначительны по сравнению с работой, которую поток с привязкой к ЦП фактически выполняет во время своего среза. И если мы предположим, что длина отрезка времени постоянна, то издержки переключения контекста также будут постоянными. Добавление большего количества работающих потоков (увеличение N) не изменит отношение работы к накладным расходам значительно.
Таким образом, это правда, что "слишком много потоков" вредно для производительности. Тем не менее, не существует надежного универсального "практического правила" для того, сколько "слишком много". И (к счастью) у вас, как правило, есть значительная свобода действий до того, как проблемы производительности "слишком многих" станут значительными.