Global Interpreter Lock (GIL) в Python был представлен, чтобы сделать обработку памяти CPython проще и обеспечить наилучшую интеграцию с языком C (например, с расширениями).
GIL - это механизм блокировки (mutex), которая не позволяет нескольким потокам выполнить один и тот же байткод. Эта блокировка, к сожалению, является необходимой, так как система управления памятью в CPython не является потокобезопасной.
Краткие сведения о GIL:
Для CPU зависимых задач интерпретатор делает проверку каждые N тиков и переключает потоки. Таким образом один поток не блокирует другие.
GIL это не проблема языка Python, а проблема реализации интерпретатора CPython. К счастью, в настоящее время существует несколько способов решения проблем GIL.
Многие видят слабость в GIL. Хотя это можно рассматривать это как благо, ведь были созданы такие библиотеки как |NumPy
|, Pandas
, которые занимают особое, уникальное положение в научном обществе.
Новое в Python 3.12
PEP 684 вводит GIL для каждого интерпретатора, так что теперь можно создавать вспомогательные интерпретаторы с уникальным GIL для каждого интерпретатора. Это позволяет программам на Python в полной мере использовать преимущества нескольких процессорных ядер. В настоящее время это доступно только через C-API, хотя ожидается, что Python API появится в версии 3.13.
Для создания интерпретатора с собственным GIL нужно использовать новую функцию Py_NewInterpreterFromConfig()
:
PyInterpreterConfig config = { .check_multi_interp_extensions = 1, .gil = PyInterpreterConfig_OWN_GIL, }; PyThreadState *tstate = NULL; PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config); if (PyStatus_Exception(status)) { return -1; } /* Новый интерпретатор теперь активен в текущем потоке. */
Новое в Python 3.13
CPython будет работать с отключенной глобальной блокировкой интерпретатора (GIL), если сборка Python3 из исходных кодов производилась с использованием опции --disable-gil
. Это экспериментальная функция, поэтому по умолчанию она не используется. Пользователям необходимо либо скомпилировать свой собственный интерпретатор, либо установить одну из экспериментальных сборок, помеченных как многопоточные. Подробнее смотрите в PEP 703 “Необязательное использование глобальной блокировки интерпретатора в CPython”.
Многопоточное выполнение позволяет полностью использовать доступную вычислительную мощность за счет параллельного запуска потоков на доступных ядрах ЦП. Хотя не все программное обеспечение выиграет от этого автоматически, программы, разработанные с учетом многопоточности, будут работать быстрее на многоядерном оборудовании.
Работа все еще продолжается: ожидаем появления некоторых ошибок и существенного снижения производительности в однопоточном режиме.
Многопоточная сборка по-прежнему поддерживает необязательный запуск с включенным GIL во время выполнения с использованием переменной окружения PYTHON_GIL
(lдоступно с версии Python 3.13) или параметра командной строки -X gil
(lдоступно с версии Python 3.13).
Чтобы проверить, скомпилирован ли текущий интерпретатор с помощью --disable-gil
, используйте sysconfig.get_config_var('Py_GIL_DISABLED')
. Чтобы проверить, действительно ли GIL отключен в запущенном процессе, можно использовать функцию sys._is_gil_enabled()
(lдоступно с версии Python 3.13).
Модули расширения C-API должны быть созданы специально для сборки со свободным потоком. Расширения, которые поддерживают запуск с отключенным GIL, должны использовать слот Py_mod_gil
. Расширения, использующие однофазный init
, для того, чтобы указать поддерживают ли они запуск с отключенным GIL, должны использовать PyUnstable_Module_SetGIL()
. Импорт расширений C, которые не используют эти механизмы, приведет к включению GIL, если только GIL не был явно отключен с помощью переменной окружения PYTHON_GIL
или параметра -X gil=0
.