Сообщить об ошибке.

Global Interpreter Lock (GIL) в Python

Краткие сведения о GIL в Python

Global Interpreter Lock (GIL) в Python был представлен, чтобы сделать обработку памяти CPython проще и обеспечить наилучшую интеграцию с языком C (например, с расширениями).

GIL - это механизм блокировки (mutex), которая не позволяет нескольким потокам выполнить один и тот же байткод. Эта блокировка, к сожалению, является необходимой, так как система управления памятью в CPython не является потокобезопасной.

Краткие сведения о GIL:

  • Одновременно может выполняться только один поток.
  • Интерпретатор Python переключается между потоками для достижения конкурентности.
  • GIL применим к CPython (стандартной реализации). Но такие как, например, Jython и IronPython не имеют GIL.
  • GIL делает однопоточные программы быстрыми.
  • Операциям ввода/вывода, обычно GIL не мешает.
  • GIL позволяет легко интегрировать непотокобезопасные библиотеки на языке C
  • Благодаря GIL есть много высокопроизводительных расширений/модулей, написанных на языке C.

Для CPU зависимых задач интерпретатор делает проверку каждые N тиков и переключает потоки. Таким образом один поток не блокирует другие.

GIL это не проблема языка Python, а проблема реализации интерпретатора CPython. К счастью, в настоящее время существует несколько способов решения проблем GIL.

Многие видят слабость в GIL. Хотя это можно рассматривать это как благо, ведь были созданы такие библиотеки как |NumPy|, Pandas, которые занимают особое, уникальное положение в научном обществе.

GIL для каждого интерпретатора

Новое в 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;
}
/* Новый интерпретатор теперь активен в текущем потоке. */

CPython со свободными потоками

Новое в 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.