Подтвердить что ты не робот

Количество процессорного ядра и размер пула потоков

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

Это правда? Если нет, каковы основополагающие принципы, нарушающие эти претензии (в частности, касающиеся java)?

4b9b3361

Ответ 1

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

Пару вещей бесспорная истина:

  1. Больше потоков означает больше использования памяти. Каждый поток требует стека потока. Для недавних виртуальных машин HotSpot минимальный размер стека потоков составляет 64 КБ, а по умолчанию он может достигать 1 МБ. Это может быть значительным. Кроме того, любой живой поток может владеть или совместно использовать объекты в куче, независимо от того, работает ли он в данный момент. Поэтому разумно ожидать, что большее количество потоков означает больший рабочий объем памяти.

  2. JVM не может иметь больше работающих потоков, чем есть ядра (или ядра с гиперпоточностью или что-то еще) на исполнительном оборудовании. Автомобиль не будет работать без двигателя, а поток не будет работать без сердечника.

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

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

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

Теперь очевидно, что "слишком много" потоков может привести к значительному снижению производительности, просто используя слишком много памяти. (Представьте, что у вас есть 4 ГБ физической памяти, и вы создаете 8 000 потоков со стеками 1 МБ. Это рецепт для перебора виртуальной памяти.)

Но как насчет других вещей? Может ли слишком много потоков вызвать чрезмерное переключение контекста?

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

  • синхронизация особенно расточительно; например, используя Object.notifyAll() когда Object.notify() будет лучше, ИЛИ
  • синхронизация в очень сложной структуре данных, ИЛИ
  • выполняется слишком много синхронизации относительно объема полезной работы, которую выполняет каждый поток, ИЛИ
  • пытаясь сделать слишком много ввода-вывода параллельно.

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

Другой момент заключается в том, что при отсутствии вышеупомянутых смешанных факторов наличие большего количества потоков не приведет к увеличению переключений контекста. Если ваше приложение имеет N исполняемых потоков, конкурирующих за M процессоров, и потоки являются чисто вычислительными и свободными от конкуренции, то планировщик потоков операционной системы попытается сократить временной интервал между ними. Но длина временного среза, вероятно, будет измеряться в десятых долях секунды (или более), поэтому издержки переключения контекста незначительны по сравнению с работой, которую поток с привязкой к ЦП фактически выполняет во время своего среза. И если мы предположим, что длина отрезка времени постоянна, то издержки переключения контекста также будут постоянными. Добавление большего количества работающих потоков (увеличение N) не изменит отношение работы к накладным расходам значительно.


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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

На самом деле, я прочитал в одной книге, что сохранение количества потоков в два раза больше ядер ЦП является хорошей практикой.