Spec-Zone.ru › Python 3.14

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

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

«Главный» интерпретатор — это первый интерпретатор, созданный при инициализации среды выполнения. Обычно он является единственным интерпретатором Python в процессе. В отличие от субинтерпретаторов, главный интерпретатор выполняет уникальные обязанности на уровне всего процесса, например обработку сигналов. Он также отвечает за выполнение кода во время инициализации среды выполнения и обычно является активным интерпретатором во время её завершения. Функция PyInterpreterState_Main() возвращает указатель на его состояние.

Переключаться между субинтерпретаторами можно с помощью функции PyThreadState_Swap(). Создавать и уничтожать их можно с помощью следующих функций:

type PyInterpreterConfig

Структура, содержащая большинство параметров для настройки субинтерпретатора. Её значения используются только в Py_NewInterpreterFromConfig() и никогда не изменяются средой выполнения.

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

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

int use_main_obmalloc

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

Если значение равно 0, то check_multi_interp_extensions должно быть равно 1 (ненулевому значению). Если значение равно 1, то gil не должно быть равно PyInterpreterConfig_OWN_GIL.

int allow_fork

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

Обратите внимание: модуль subprocess продолжает работать, даже если создание ответвлений запрещено.

int allow_exec

Если значение равно 0, среда выполнения не будет поддерживать замену текущего процесса с помощью exec (например, os.execv()) ни в одном потоке, в котором в данный момент активен субинтерпретатор. В противном случае использование exec не ограничено.

Обратите внимание: модуль subprocess продолжает работать, даже если использование exec запрещено.

int allow_threads

Если значение равно 0, модуль threading субинтерпретатора не будет создавать потоки. В противном случае потоки разрешены.

int allow_daemon_threads

Если значение равно 0, модуль threading субинтерпретатора не будет создавать потоки-демоны. В противном случае потоки-демоны разрешены (если allow_threads не равно нулю).

int check_multi_interp_extensions

Если значение равно 0, можно импортировать все модули расширений, включая устаревшие модули (с однофазной инициализацией), в любом потоке, в котором в данный момент активен субинтерпретатор. В противном случае можно импортировать только модули расширений с многофазной инициализацией (см. PEP 489). (Также см. Py_mod_multiple_interpreters.)

Значение должно быть равно 1 (ненулевому), если use_main_obmalloc равно 0.

int gil

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

PyInterpreterConfig_DEFAULT_GIL

Использовать значение по умолчанию (PyInterpreterConfig_SHARED_GIL).

PyInterpreterConfig_SHARED_GIL

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

PyInterpreterConfig_OWN_GIL

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

Если значение равно PyInterpreterConfig_OWN_GIL, то PyInterpreterConfig.use_main_obmalloc должно быть равно 0.

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

Создаёт новый субинтерпретатор. Это (почти) полностью отдельная среда для выполнения кода Python. В частности, в новом интерпретаторе имеются отдельные, независимые версии всех импортированных модулей, включая основные модули builtins, __main__ и sys. Таблица загруженных модулей (sys.modules) и путь поиска модулей (sys.path) также отдельные. В новой среде нет переменной sys.argv. В ней создаются новые файловые объекты стандартных потоков ввода-вывода sys.stdin, sys.stdout и sys.stderr (однако они ссылаются на те же базовые файловые дескрипторы).

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

В случае успеха в tstate_p будет записан указатель на первое состояние потока, созданное в новом субинтерпретаторе. Это состояние потока присоединено. Обратите внимание: фактический поток не создаётся; см. обсуждение состояний потоков ниже. Если создать новый интерпретатор не удалось, в tstate_p записывается NULL; исключение не устанавливается, поскольку состояние исключения хранится в присоединённом состоянии потока, которого может не существовать.

Как и перед вызовом любой другой функции Python/C API, перед вызовом этой функции должно существовать присоединённое состояние потока, однако после возврата оно может быть отсоединено. В случае успеха возвращённое состояние потока будет присоединено. Если субинтерпретатор создан с собственным GIL, то присоединённое состояние потока вызывающего интерпретатора будет отсоединено. После возврата функции состояние потока нового интерпретатора будет присоединено к текущему потоку, а предыдущее присоединённое состояние потока останется отсоединённым.

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

Субинтерпретаторы наиболее эффективны, когда они изолированы друг от друга и некоторые возможности ограничены:

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);
}

Обратите внимание: конфигурация используется только на короткое время и не изменяется. Во время инициализации значения конфигурации преобразуются в различные значения PyInterpreterState. Копия конфигурации, доступная только для чтения, может храниться внутри PyInterpreterState.

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

  • Для модулей с многофазной инициализацией, например PyModule_FromDefAndSpec(), для каждого интерпретатора создаётся и инициализируется отдельный объект модуля. Между этими объектами модулей совместно используются только статические переменные и глобальные переменные уровня C.
  • Для модулей с устаревшей однофазной инициализацией, например PyModule_Create(), при первом импорте конкретного расширения оно инициализируется обычным образом, а (поверхностная) копия словаря модуля сохраняется. Когда то же расширение импортируется другим (суб-)интерпретатором, создаётся новый модуль и заполняется содержимым этой копии; функция init расширения не вызывается. Таким образом, объекты в словаре модуля оказываются общими для (суб-)интерпретаторов, что может привести к нежелательному поведению (см. раздел Ошибки и предостережения ниже).

    Обратите внимание: это отличается от ситуации, когда расширение импортируется после полной повторной инициализации интерпретатора вызовами Py_FinalizeEx() и Py_Initialize(); в этом случае функция initmodule расширения вызывается снова. Как и при многофазной инициализации, это означает, что между этими модулями совместно используются только статические переменные и глобальные переменные уровня C.

PyThreadState *Py_NewInterpreter(void)
Часть стабильного ABI.

Создаёт новый субинтерпретатор. По сути, это просто оболочка над Py_NewInterpreterFromConfig() с конфигурацией, сохраняющей существующее поведение. В результате создаётся неизолированный субинтерпретатор, который использует GIL главного интерпретатора совместно с ним, разрешает создание ответвлений и exec, разрешает потоки-демоны и модули с однофазной инициализацией.

void Py_EndInterpreter(PyThreadState *tstate)
Часть стабильного ABI.

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

Py_FinalizeEx() уничтожит все субинтерпретаторы, которые к этому моменту не были уничтожены явно.

Отдельный GIL для каждого интерпретатора

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

С помощью Py_NewInterpreterFromConfig() можно создать субинтерпретатор, полностью изолированный от других интерпретаторов, в том числе с собственным GIL. Главное преимущество такой изоляции состоит в том, что такой интерпретатор может выполнять код Python, не блокируясь другими интерпретаторами и не блокируя их. Таким образом, один процесс Python может в полной мере использовать несколько ядер ЦП при выполнении кода Python. Изоляция также способствует иному подходу к параллелизму, чем простое использование потоков. (См. PEP 554 и PEP 684.)

При использовании изолированного интерпретатора необходимо внимательно следить за сохранением изоляции. В частности, нельзя совместно использовать объекты или изменяемое состояние без гарантий потокобезопасности. Даже объекты, которые в остальном неизменяемы (например, None, (1, 5)), обычно нельзя использовать совместно из-за счётчика ссылок. Один из простых, но менее эффективных способов обойти это ограничение — использовать глобальную блокировку при любом обращении к некоторому состоянию (или объекту). Другой вариант — сделать фактически неизменяемые объекты (например, целые числа или строки) безопасными, несмотря на их счётчики ссылок, превратив их в бессмертные. Именно так поступили со встроенными синглтонами, небольшими целыми числами и рядом других встроенных объектов.

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

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

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

Поскольку субинтерпретаторы (и главный интерпретатор) являются частью одного процесса, изоляция между ними не идеальна — например, с помощью низкоуровневых операций с файлами, таких как os.close(), они могут (случайно или злонамеренно) влиять на открытые файлы друг друга. Из-за особенностей совместного использования расширений (суб-)интерпретаторами некоторые расширения могут работать неправильно; особенно вероятно это при использовании однофазной инициализации или (статических) глобальных переменных. Объекты, созданные в одном субинтерпретаторе, можно поместить в пространство имён другого (суб-)интерпретатора; по возможности этого следует избегать.

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

Также обратите внимание, что сочетать эту функциональность с API PyGILState_* следует осторожно, поскольку эти API предполагают взаимно однозначное соответствие между состояниями потоков Python и потоками на уровне ОС, а наличие субинтерпретаторов нарушает это предположение. Настоятельно рекомендуется не переключать субинтерпретаторы между парными вызовами PyGILState_Ensure() и PyGILState_Release(). Кроме того, расширения (например, ctypes), использующие эти API для вызова кода Python из потоков, созданных не средствами Python, вероятно, будут работать неправильно при использовании субинтерпретаторов.

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

type PyInterpreterState
Часть ограниченного API (как непрозрачная структура).

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

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

Изменено в версии 3.12: PEP 684 добавил возможность использовать отдельный GIL для каждого интерпретатора. См. Py_NewInterpreterFromConfig().

PyInterpreterState *PyInterpreterState_Get(void)
Часть стабильного ABI с версии 3.9.

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

Вызывает фатальную ошибку, если нет присоединённого состояния потока. Не может вернуть NULL.

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

int64_t PyInterpreterState_GetID(PyInterpreterState *interp)
Часть стабильного ABI с версии 3.7.

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

У вызывающего кода должно быть присоединённое состояние потока.

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

PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)
Возвращаемое значение: заимствованная ссылка.Часть стабильного ABI с версии 3.8.

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

Это не замена 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 «Добавление API вычисления кадра в CPython».

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

void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)

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

См. PEP 523 «Добавление API вычисления кадра в CPython».

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

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

Все перечисленные ниже функции необходимо вызывать после Py_Initialize().

Изменено в версии 3.7: Py_Initialize() теперь инициализирует GIL и устанавливает присоединённое состояние потока.

PyInterpreterState *PyInterpreterState_New()
Часть стабильного ABI.

Создаёт новый объект состояния интерпретатора. Присоединённое состояние потока не требуется, но может существовать, если необходимо сериализовать вызовы этой функции.

Вызывает событие аудита cpython.PyInterpreterState_New без аргументов.

void PyInterpreterState_Clear(PyInterpreterState *interp)
Часть стабильного ABI.

Сбрасывает всю информацию в объекте состояния интерпретатора. Для интерпретатора должно существовать присоединённое состояние потока.

Вызывает событие аудита cpython.PyInterpreterState_Clear без аргументов.

void PyInterpreterState_Delete(PyInterpreterState *interp)
Часть стабильного ABI.

Уничтожает объект состояния интерпретатора. Для целевого интерпретатора не должно быть присоединённого состояния потока. Состояние интерпретатора должно быть сброшено предыдущим вызовом PyInterpreterState_Clear().

Расширенная поддержка отладчиков

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

PyInterpreterState *PyInterpreterState_Head()

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

PyInterpreterState *PyInterpreterState_Main()

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

PyInterpreterState *PyInterpreterState_Next(PyInterpreterState *interp)

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

PyThreadState *PyInterpreterState_ThreadHead(PyInterpreterState *interp)

Возвращает указатель на первый объект PyThreadState в списке потоков, связанных с интерпретатором interp.

PyThreadState *PyThreadState_Next(PyThreadState *tstate)

Возвращает следующий объект состояния потока после tstate в списке всех таких объектов, принадлежащих одному объекту PyInterpreterState.

© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/c-api/subinterpreters.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API