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

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

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

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

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

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

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

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

Ответ 1

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

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

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

Ответ 2

Другое решение: http://docs.python.org/library/multiprocessing.html

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

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

Ответ 3

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

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

Ответ 4

На протяжении многих лет я нашел следующее правило: если рабочие зависят от какого-либо общего состояния, я использую один процесс многопроцессорности на ядро ​​(привязка к ЦП), а на ядро ​​- пул исправлений рабочих потоков (I/O). ОС позаботится о том, чтобы настроить различные процессы Python на ядра.

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

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

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

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

Att, Лео