> **Источник:** https://python-all.ru/3/c-api/subinterpreters.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# Несколько интерпретаторов в одном процессе Python

Хотя в большинстве случаев достаточно встроить один интерпретатор Python, бывают ситуации, когда требуется создать несколько независимых интерпретаторов в одном процессе и даже в одном потоке. Под-интерпретаторы позволяют это сделать.

«Главный» интерпретатор – это первый интерпретатор, создаваемый при инициализации среды выполнения. Обычно он является единственным интерпретатором Python в процессе. В отличие от под-интерпретаторов, главный интерпретатор обладает уникальными общепроцессными обязанностями, такими как обработка сигналов. Он также отвечает за выполнение при инициализации среды выполнения и обычно является активным интерпретатором при завершении работы среды выполнения. Функция [`PyInterpreterState_Main()`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterState_Main) возвращает указатель на его состояние.

Переключаться между под-интерпретаторами можно с помощью функции [`PyThreadState_Swap()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Swap). Создавать и удалять их можно с помощью следующих функций:

#### `type PyInterpreterConfig`

Структура, содержащая большинство параметров для настройки под-интерпретатора. Её значения используются только в [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig) и никогда не изменяются средой выполнения.

Добавлено в версии 3.12.

Поля структуры:

#### `int use_main_obmalloc`

Если это `0`, то под-интерпретатор будет использовать собственное состояние аллокатора «объектов». В противном случае он будет использовать (разделять) состояние главного интерпретатора.

Если это `0`, то [`check_multi_interp_extensions`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig.check_multi_interp_extensions) должен быть `1` (ненулевым). Если это `1`, то [`gil`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig.gil) не должен быть [`PyInterpreterConfig_OWN_GIL`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig_OWN_GIL).

#### `int allow_fork`

Если это `0`, то среда выполнения не будет поддерживать создание форка процесса в любом потоке, где в данный момент активен под-интерпретатор. В противном случае форк не ограничен.

Обратите внимание, что модуль [`subprocess`](https://python-all.ru/3/library/subprocess.html#module-subprocess) по-прежнему работает, когда форк запрещён.

#### `int allow_exec`

Если это `0`, то среда выполнения не будет поддерживать замену текущего процесса через exec (например, [`os.execv()`](https://python-all.ru/3/library/os.html#os.execv)) в любом потоке, где в данный момент активен под-интерпретатор. В противном случае exec не ограничен.

Обратите внимание, что модуль [`subprocess`](https://python-all.ru/3/library/subprocess.html#module-subprocess) по-прежнему работает, когда exec запрещён.

#### `int allow_threads`

Если это `0`, то модуль [`threading`](https://python-all.ru/3/library/threading.html#module-threading) под-интерпретатора не будет создавать потоки. В противном случае потоки разрешены.

#### `int allow_daemon_threads`

Если это `0`, то модуль [`threading`](https://python-all.ru/3/library/threading.html#module-threading) под-интерпретатора не будет создавать потоки-демоны. В противном случае потоки-демоны разрешены (при условии, что [`allow_threads`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig.allow_threads) не равен нулю).

#### `int check_multi_interp_extensions`

Если это `0`, то все модули расширений могут быть импортированы, включая устаревшие модули (с однофазной инициализацией), в любом потоке, где активен под-интерпретатор. В противном случае могут быть импортированы только модули расширений с многофазной инициализацией (см. [**PEP 489**](https://python-all.ru/3/c-api/subinterpreters.html)). (См. также [`Py_mod_multiple_interpreters`](https://python-all.ru/3/c-api/module.html#c.Py_mod_multiple_interpreters).)

Это должно быть `1` (ненулевым), если [`use_main_obmalloc`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig.use_main_obmalloc) равно `0`.

#### `int gil`

Это определяет режим работы GIL для под-интерпретатора. Он может быть одним из следующих:

#### `PyInterpreterConfig_DEFAULT_GIL`

Использовать выбор по умолчанию ([`PyInterpreterConfig_SHARED_GIL`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig_SHARED_GIL)).

#### `PyInterpreterConfig_SHARED_GIL`

Использовать (разделять) GIL главного интерпретатора.

#### `PyInterpreterConfig_OWN_GIL`

Использовать собственный GIL под-интерпретатора.

Если это [`PyInterpreterConfig_OWN_GIL`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig_OWN_GIL), то [`PyInterpreterConfig.use_main_obmalloc`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterConfig.use_main_obmalloc) должен быть `0`.

#### `PyStatus Py_NewInterpreterFromConfig(PyThreadState **tstate_p, const PyInterpreterConfig *config)`

Создаёт новый под-интерпретатор. Это (почти) полностью независимое окружение для выполнения кода Python. В частности, новый интерпретатор имеет отдельные, независимые версии всех импортированных модулей, включая фундаментальные модули [`builtins`](https://python-all.ru/3/library/builtins.html#module-builtins), [`__main__`](https://python-all.ru/3/library/__main__.html#module-__main__) и [`sys`](https://python-all.ru/3/library/sys.html#module-sys). Таблица загруженных модулей (`sys.modules`) и путь поиска модулей (`sys.path`) также отдельные. В новом окружении нет переменной `sys.argv` . У него есть новые файловые объекты стандартных потоков ввода-вывода `sys.stdin`, `sys.stdout` и `sys.stderr` (однако они ссылаются на те же нижележащие файловые дескрипторы).

Переданный *config* управляет параметрами, с которыми инициализируется интерпретатор.

В случае успеха *tstate\_p* будет установлен в первое [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state), созданное в новом под-интерпретаторе. Это состояние потока [присоединено](https://python-all.ru/3/glossary.html#term-attached-thread-state). Обратите внимание, что при этом не создаётся реальный поток; см. обсуждение состояний потока ниже. Если создание нового интерпретатора не удалось, *tstate\_p* устанавливается в `NULL`; исключение не устанавливается, так как состояние исключения хранится в присоединённом состоянии потока, которое может не существовать.

Как и для всех остальных функций Python/C API, перед вызовом этой функции должно присутствовать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state), но после возврата оно может быть отсоединено. В случае успеха возвращённое состояние потока будет присоединено. Если под-интерпретатор создаётся с собственным [GIL](https://python-all.ru/3/glossary.html#term-GIL), то присоединённое состояние потока вызывающего интерпретатора будет отсоединено. Когда функция возвращается, [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state) нового интерпретатора будет присоединено к текущему потоку, а присоединённое состояние потока предыдущего интерпретатора останется отсоединённым.

Добавлено в версии 3.12.

Под-интерпретаторы наиболее эффективны при изоляции друг от друга, с ограничением определённой функциональности:

```c
PyInterpreterConfig config = {
    .use_main_obmalloc = 0,
    .allow_fork = 0,
    .allow_exec = 0,
    .allow_threads = 1,
    .allow_daemon_threads = 0,
    .check_multi_interp_extensions = 1,
    .gil = PyInterpreterConfig_OWN_GIL,
};
PyThreadState *tstate = NULL;
PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
if (PyStatus_Exception(status)) {
    Py_ExitStatusException(status);
}
```

Обратите внимание, что config используется только кратковременно и не изменяется. Во время инициализации значения config преобразуются в различные значения [`PyInterpreterState`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterState). Копия config только для чтения может быть сохранена внутри на `PyInterpreterState`.

Модули расширения совместно используются (под-)интерпретаторами следующим образом:

- Для модулей, использующих многофазную инициализацию, например [`PyModule_FromDefAndSpec()`](https://python-all.ru/3/c-api/module.html#c.PyModule_FromDefAndSpec), для каждого интерпретатора создаётся и инициализируется отдельный объект модуля. Между этими объектами модулей совместно используются только статические и глобальные переменные на уровне C.
- Для модулей, использующих устаревшую [однофазную инициализацию](https://python-all.ru/3/c-api/extension-modules.html#single-phase-initialization), например [`PyModule_Create()`](https://python-all.ru/3/c-api/module.html#c.PyModule_Create), при первом импорте конкретного расширения оно инициализируется обычным образом, а (поверхностная) копия его словаря модуля сохраняется. Когда то же расширение импортируется другим (под-)интерпретатором, создаётся новый модуль и заполняется содержимым этой копии; функция `init` расширения не вызывается. Объекты в словаре модуля таким образом оказываются совместно используемыми между (под-)интерпретаторами, что может привести к нежелательному поведению (см. [Ошибки и предостережения](https://python-all.ru/3/c-api/subinterpreters.html#bugs-and-caveats) ниже).

  Обратите внимание, что это отличается от ситуации, когда расширение импортируется после полной повторной инициализации интерпретатора вызовом [`Py_FinalizeEx()`](https://python-all.ru/3/c-api/interp-lifecycle.html#c.Py_FinalizeEx) и [`Py_Initialize()`](https://python-all.ru/3/c-api/interp-lifecycle.html#c.Py_Initialize); в этом случае функция `initmodule` расширения *вызывается* снова. Как и при многофазной инициализации, это означает, что между этими модулями совместно используются только статические и глобальные переменные на уровне C.

#### `PyThreadState *Py_NewInterpreter(void)`

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*

Создаёт новый под-интерпретатор. По сути, это просто обёртка вокруг [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig) с config, который сохраняет существующее поведение. Результатом является неизолированный под-интерпретатор, который разделяет GIL главного интерпретатора, допускает fork/exec, разрешает фоновые потоки и допускает модули с однофазной инициализацией.

#### `void Py_EndInterpreter(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*

Уничтожает (под-)интерпретатор, представленный заданным [состоянием потока](https://python-all.ru/3/glossary.html#term-thread-state). Заданное состояние потока должно быть [присоединено](https://python-all.ru/3/glossary.html#term-attached-thread-state). После возврата вызова не будет присоединённого состояния потока. Все состояния потоков, связанные с этим интерпретатором, уничтожаются.

[`Py_FinalizeEx()`](https://python-all.ru/3/c-api/interp-lifecycle.html#c.Py_FinalizeEx) уничтожит все под-интерпретаторы, которые не были явно уничтожены к этому моменту.

## Индивидуальный GIL для каждого интерпретатора

Добавлено в версии 3.12.

С помощью [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig) можно создать под-интерпретатор, который полностью изолирован от других интерпретаторов, включая собственный GIL. Самое важное преимущество такой изоляции в том, что такой интерпретатор может выполнять код Python без блокировки другими интерпретаторами и не блокируя другие. Таким образом, один процесс Python может по-настоящему использовать несколько ядер CPU при выполнении кода Python. Изоляция также поощряет иной подход к параллелизму, отличный от простого использования потоков. (См. [**PEP 554**](https://python-all.ru/3/c-api/subinterpreters.html) и [**PEP 684**](https://python-all.ru/3/c-api/subinterpreters.html).)

Использование изолированного интерпретатора требует бдительности для сохранения этой изоляции. Это особенно означает, что нельзя совместно использовать объекты или изменяемое состояние без гарантий потокобезопасности. Даже объекты, которые в остальном неизменяемы (например, `None`, `(1, 5)`), обычно не могут быть использованы совместно из-за счётчика ссылок. Один простой, но менее эффективный подход – использовать глобальную блокировку при любом использовании некоторого состояния (или объекта). С другой стороны, эффективно неизменяемые объекты (такие как целые числа или строки) можно сделать безопасными, несмотря на их счётчики ссылок, сделав их [бессмертными](https://python-all.ru/3/glossary.html#term-immortal). Фактически, это уже сделано для встроенных синглтонов, маленьких целых чисел и ряда других встроенных объектов.

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

Кроме того, одна из главных проблем использования нескольких изолированных интерпретаторов – как безопасно (не нарушая изоляцию) и эффективно общаться между ними. Среда выполнения и стандартная библиотека пока не предоставляют стандартного подхода для этого. Будущий модуль стандартной библиотеки поможет уменьшить усилия по сохранению изоляции и предоставит эффективные инструменты для обмена (и совместного использования) данными между интерпретаторами.

## Ошибки и предостережения

Поскольку под-интерпретаторы (и основной интерпретатор) являются частью одного процесса, изоляция между ними не идеальна – например, используя низкоуровневые файловые операции, такие как [`os.close()`](https://python-all.ru/3/library/os.html#os.close), они могут (случайно или злонамеренно) влиять на открытые файлы друг друга. Из-за того, как расширения совместно используются между (под-)интерпретаторами, некоторые расширения могут работать неправильно; это особенно вероятно при использовании однофазной инициализации или (статических) глобальных переменных. Можно вставить объекты, созданные в одном под-интерпретаторе, в пространство имён другого (под-)интерпретатора; этого следует избегать по возможности.

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

Также обратите внимание, что комбинирование этой функциональности с API `PyGILState_*` является деликатным, поскольку эти API предполагают взаимно однозначное соответствие между состояниями потоков Python и потоками уровня ОС, а это предположение нарушается наличием под-интерпретаторов. Настоятельно рекомендуется не переключать под-интерпретаторы между парой соответствующих вызовов [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure) и [`PyGILState_Release()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Release). Более того, расширения (такие как [`ctypes`](https://python-all.ru/3/library/ctypes.html#module-ctypes)), использующие эти API для вызова кода Python из потоков, созданных не в Python, вероятно, будут работать неправильно при использовании под-интерпретаторов.

## Высокоуровневые API

#### `type PyInterpreterState`

*Часть [Limited API](https://python-all.ru/3/c-api/stable.html#stable) (как непрозрачная структура).*

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

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

Изменено в версии 3.12: [**PEP 684**](https://python-all.ru/3/c-api/subinterpreters.html) ввёл возможность [индивидуального GIL для каждого интерпретатора](https://python-all.ru/3/c-api/subinterpreters.html#per-interpreter-gil). См. [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig).

#### `PyInterpreterState *PyInterpreterState_Get(void)`

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) начиная с версии 3.9.*

Получает текущий интерпретатор.

Вызывает фатальную ошибку, если [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) отсутствует. Функция не может вернуть NULL.

Добавлено в версии 3.9.

#### `int64_t PyInterpreterState_GetID(PyInterpreterState *interp)`

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) начиная с версии 3.7.*

Возвращает уникальный идентификатор интерпретатора. Если при этом произошла ошибка, возвращается `-1` и устанавливается исключение.

Вызывающий должен иметь [прикреплённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).

Добавлено в версии 3.7.

#### `PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)`

*Возвращаемое значение: заимствованная ссылка.*

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) начиная с версии 3.8.*

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

Это не замена [`PyModule_GetState()`](https://python-all.ru/3/c-api/module.html#c.PyModule_GetState), который расширения должны использовать для хранения информации о состоянии интерпретатора.

Возвращаемый словарь заимствуется из интерпретатора и действителен до завершения работы интерпретатора.

Добавлено в версии 3.8.

#### `typedef PyObject *(*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)`

Тип функции вычисления фрейма.

Параметр *throwflag* используется методом `throw()` генераторов: если он не равен нулю, обрабатывается текущее исключение.

Изменено в версии 3.9: Теперь функция принимает параметр *tstate*.

Изменено в версии 3.11: Параметр *frame* изменился с `PyFrameObject*` на `_PyInterpreterFrame*`.

#### `_PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp)`

Возвращает функцию вычисления фрейма.

См. [**PEP 523**](https://python-all.ru/3/c-api/subinterpreters.html) «Добавление API вычисления фрейма в CPython».

Добавлено в версии 3.9.

#### `void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)`

Устанавливает функцию вычисления фрейма.

См. [**PEP 523**](https://python-all.ru/3/c-api/subinterpreters.html) «Добавление API вычисления фрейма в CPython».

Добавлено в версии 3.9.

## Низкоуровневые API

Все следующие функции должны вызываться после [`Py_Initialize()`](https://python-all.ru/3/c-api/interp-lifecycle.html#c.Py_Initialize).

Изменено в версии 3.7: [`Py_Initialize()`](https://python-all.ru/3/c-api/interp-lifecycle.html#c.Py_Initialize) теперь инициализирует [GIL](https://python-all.ru/3/glossary.html#term-GIL) и устанавливает [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).

#### `PyInterpreterState *PyInterpreterState_New()`

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*

Создаёт новый объект состояния интерпретатора. [Присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) не требуется, но может опционально существовать, если необходимо сериализовать вызовы этой функции.

Возбуждает [событие аудита](https://python-all.ru/3/library/sys.html#auditing) `cpython.PyInterpreterState_New` без аргументов.

#### `void PyInterpreterState_Clear(PyInterpreterState *interp)`

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*

Сбрасывает всю информацию в объекте состояния интерпретатора. Для интерпретатора должно существовать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).

Возбуждает [событие аудита](https://python-all.ru/3/library/sys.html#auditing) `cpython.PyInterpreterState_Clear` без аргументов.

#### `void PyInterpreterState_Delete(PyInterpreterState *interp)`

*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*

Уничтожает объект состояния интерпретатора. Для целевого интерпретатора **не должно быть** [прикреплённого состояния потока](https://python-all.ru/3/glossary.html#term-attached-thread-state). Состояние интерпретатора должно быть сброшено предыдущим вызовом [`PyInterpreterState_Clear()`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterState_Clear).

## Поддержка расширенной отладки

Эти функции предназначены только для использования расширенными инструментами отладки.

#### `PyInterpreterState *PyInterpreterState_Head()`

Возвращает объект состояния интерпретатора, находящийся в начале списка всех таких объектов.

#### `PyInterpreterState *PyInterpreterState_Main()`

Возвращает объект состояния основного интерпретатора.

#### `PyInterpreterState *PyInterpreterState_Next(PyInterpreterState *interp)`

Возвращает следующий объект состояния интерпретатора после *interp* из списка всех таких объектов.

#### `PyThreadState *PyInterpreterState_ThreadHead(PyInterpreterState *interp)`

Возвращает указатель на первый объект [`PyThreadState`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState) в списке потоков, связанных с интерпретатором *interp*.

#### `PyThreadState *PyThreadState_Next(PyThreadState *tstate)`

Возвращает следующий объект состояния потока после *tstate* из списка всех таких объектов, принадлежащих тому же объекту [`PyInterpreterState`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterState).
