Почему значение max_workers по умолчанию для ThreadPoolExecutor определяется на основе количества процессоров?

В документации для concurrent.futures.ThreadPoolExecutor говорится:

Изменено в версии 3.5: если max_workers равно None или не задано, по умолчанию будет указано количество процессоров на машине, умноженное на 5, при условии, что ThreadPoolExecutor часто используется для перекрытия ввода-вывода вместо работы ЦП и количество рабочих должно быть больше, чем количество рабочих для ProcessPoolExecutor.

Я хочу понять, почему значение max_workers по умолчанию зависит от количества процессоров. Независимо от того, сколько у меня процессоров, в любой момент времени может работать только один поток Python.

Предположим, что каждый поток интенсивно использует операции ввода-вывода и проводит только 10 % своего времени в ЦП и 90 % своего времени в ожидании ввода-вывода. Предположим, что у нас есть 2 процессора. Мы можем запустить только 10 потоков, чтобы использовать ЦП на 100%. Мы больше не можем использовать ЦП, потому что в любой момент времени работает только один поток. Это справедливо даже при наличии 4 процессоров.

Так почему же значение по умолчанию max_workers определяется количеством процессоров?


person Lone Learner    schedule 18.05.2019    source источник
comment
Вы говорите о GIL, но это деталь реализации. В других средах выполнения этой проблемы нет.   -  person Sraw    schedule 18.05.2019


Ответы (2)


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

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

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

person user2357112 supports Monica    schedule 18.05.2019
comment
В таком случае, почему бы не произвольное число, например 10? - person Lone Learner; 18.05.2019
comment
@LoneLearner: Это не лучше, чем то, что они выбрали. - person user2357112 supports Monica; 18.05.2019

Реализация потока CPython очень легкая. В основном он отправляет это в ОС с некоторым учетом GIL (и сигнала умение обращаться). Увеличить количество потоков пропорционально ядрам обычно не получается. Поскольку потоки управляются операционной системой со многими ядрами, ОС становится жадной и пытается запустить как можно больше готовых потоков, если есть переключение контекста потока. Все они пытаются заполучить GIL, и только одному это удается. Это приводит к большому количеству потерь — хуже, чем линейный расчет, предполагающий, что в данный момент времени может выполняться только один поток. Если вы используете чистые потоки, привязанные к процессору, в исполнителе, нет причин связывать его с ядрами из-за этого. Но мы не должны лишать пользователей, которым действительно нужна мощность процессора и которые согласны с выпуском GIL для использования ядер. Таким образом, возможно, в этом случае значение по умолчанию должно быть связано с количеством ядер - если вы предполагаете, что большинство людей, использующих Python, знают, что они делают.

Теперь, если потоки в исполнителе связаны с вводом-выводом, то вы правильно упомянули, что максимальная мощность составляет 1/p, где p — это доля ЦП, необходимая каждому потоку. Для определения значения по умолчанию невозможно заранее узнать, что такое р. Минимум по умолчанию 0,2 (минимум 5 потоков) выглядит не так уж плохо. Но обычно я предполагаю, что это p будет намного ниже, поэтому ограничивающим фактором никогда не может быть ЦП (но если это так, мы снова сталкиваемся с проблемой перегрузки ЦП из-за нескольких ядер, как указано выше). Таким образом, привязка к количеству ядер, вероятно, не окажется небезопасной (если только потоки не имеют интенсивной обработки или у вас слишком много ядер!).

person Prodipta Ghosh    schedule 19.08.2020