Обходной путь глобальной блокировки интерпретатора Python (GIL) в многоядерных системах с использованием набора задач в Linux?

StackOverflow https://stackoverflow.com/questions/990102

Вопрос

Итак, я только что закончил смотреть этот доклад о блокировке глобального интерпретатора Python (GIL) http://blip.tv/file/2232410.

Суть этого в том, что GIL - довольно хороший дизайн для одноядерных систем (Python, по сути, оставляет обработку потоков / планирование на усмотрение операционной системы).Но это может серьезно иметь неприятные последствия для многоядерных систем, и в конечном итоге потоки с интенсивным вводом-выводом будут сильно заблокированы потоками с интенсивным использованием процессора, из-за переключения контекста, проблемы с ctrl-C [*] и так далее.

Итак, поскольку GIL ограничивает нас в основном выполнением программы Python на одном процессоре, я подумал, почему бы не принять это и просто использовать taskset в Linux, чтобы установить привязку программы к определенному ядру / процессору в системе (особенно в ситуации с несколькими приложениями Python, работающими в многоядерной системе)?

Итак, в конечном счете, мой вопрос заключается в следующем:кто-нибудь пробовал использовать taskset в Linux с приложениями Python (особенно при запуске нескольких приложений в системе Linux, чтобы можно было использовать несколько ядер с одним или двумя приложениями Python, привязанными к определенному ядру), и если да, то каковы были результаты?стоит ли это делать?Ухудшает ли это ситуацию при определенных рабочих нагрузках?Я планирую сделать это и протестировать (в основном посмотреть, занимает ли программа больше или меньше времени для запуска), но хотел бы услышать от других о вашем опыте.

Дополнение:Дэвид Бизли (парень, выступающий с докладом в связанном видео) отметил, что некоторые расширения C / C ++ вручную снимают блокировку GIL, и если эти расширения оптимизированы для многоядерных (т.е.научный или числовой анализ данных / и т.д.), То вместо того, чтобы получать преимущества многоядерности для обработки чисел, расширение будет эффективно повреждено, поскольку оно ограничено одним ядром (что потенциально значительно замедляет работу вашей программы).С другой стороны, если вы не используете расширения, подобные этому

Причина, по которой я не использую модуль многопроцессорной обработки, заключается в том, что (в данном случае) часть программы сильно привязана к сетевому вводу-выводу (HTTP-запросы), поэтому наличие пула рабочих потоков - отличный способ максимально снизить производительность, поскольку поток запускает HTTP-запрос, а затем, поскольку он ожидает ввода-вывода, отказывается от GIL, и другой поток может выполнить свою задачу, так что эта часть программы может легко запускать более 100 потоков без особого ущерба для процессора и позволяет мне фактически использовать доступную пропускную способность сети.Что касается stackless Python / etc, я не слишком заинтересован в переписывании программы или замене моего стека Python (доступность также была бы проблемой).

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

Это было полезно?

Решение

Я никогда не слышал о том, чтобы кто-нибудь использовал taskset для повышения производительности с помощью Python.Это не значит, что этого не может произойти в вашем случае, но обязательно опубликуйте свои результаты, чтобы другие могли критиковать ваши методы сравнительного анализа и обеспечивать валидацию.

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

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

Другие советы

Другим решением является:http://docs.python.org/library/multiprocessing.html

Примечание 1:Это не ограничение языка Python, но не реализации CPython.

Примечание 2:Что касается affinity, у вашей операционной системы не должно возникнуть проблем с тем, чтобы сделать это самой.

Интересным решением является эксперимент, о котором сообщил Райан Келли в своем блоге: http://www.rfk.id.au/blog/entry/a-gil-adventure-threading2/

Результаты кажутся очень удовлетворительными.

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

Python GIL зависит от интерпретатора Python.Это означает, что единственный способ избежать проблем с ним при выполнении многопроцессорной обработки - это просто запустить несколько интерпретаторов (т.е.используя отдельные процессы вместо потоков для параллелизма), а затем используя какой-либо другой примитив IPC для связи между процессами (например, сокеты).При этом GIL не является проблемой при использовании потоков с блокирующими вызовами ввода-вывода.

Основная проблема GIL, как упоминалось ранее, заключается в том, что вы не можете выполнить 2 разных потока кода python одновременно.Поток, блокирующий блокирующий вызов ввода-вывода, блокируется и, следовательно, не выполняется в коде python.Это означает, что он не блокирует GIL.Если у вас есть две задачи с интенсивным использованием процессора в отдельных потоках Python, именно здесь GIL уничтожает мультиобработку в Python (только реализацию CPython, как указывалось ранее).Потому что GIL останавливает CPU # 1 от выполнения потока python, в то время как CPU # 0 занят выполнением другого потока python.

До тех пор, пока GIL не будет удален из Python, вместо потоков могут использоваться совместные подпрограммы.Из достоверных источников мне известно, что эта стратегия была реализована двумя успешными стартапами, по крайней мере в одном случае использовавшими greenlets.

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

Вы можете использовать модуль многопроцессорной обработки, который вместо создания потоков для каждой задачи создает другой процесс компилятора cpython, интерпретирующий ваш код.Это позволило бы вашему приложению использовать преимущества многоядерных систем.Единственная проблема, которую я вижу при таком подходе, заключается в том, что у вас будут значительные накладные расходы при создании всего нового стека процессов в памяти.(http://en.wikipedia.org/wiki/Thread_ (вычисления)#Как_потоки_отличаются от_процессов)

Модуль многопроцессорной обработки Python:http://docs.python.org/dev/library/multiprocessing.html

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

По поводу этого, я предполагаю, что у вас также может быть пул процессов: http://docs.python.org/dev/library/multiprocessing.html#using-a-pool-of-workers

Att, Leo

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top