Документация Python неофициальный перевод

subinterpreters.md

284 строк · 35.3 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.16/c-api/subinterpreters.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Несколько интерпретаторов в одном процессе Python89Хотя в большинстве случаев достаточно встроить один интерпретатор Python, бывают ситуации, когда требуется создать несколько независимых интерпретаторов в одном процессе и даже в одном потоке. Под-интерпретаторы позволяют это сделать.1011«Главный» интерпретатор – это первый интерпретатор, создаваемый при инициализации среды выполнения. Обычно он является единственным интерпретатором Python в процессе. В отличие от под-интерпретаторов, главный интерпретатор обладает уникальными общепроцессными обязанностями, такими как обработка сигналов. Он также отвечает за выполнение при инициализации среды выполнения и обычно является активным интерпретатором при завершении работы среды выполнения. Функция [`PyInterpreterState_Main()`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterState_Main) возвращает указатель на его состояние.1213Переключаться между под-интерпретаторами можно с помощью функции [`PyThreadState_Swap()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Swap). Создавать и удалять их можно с помощью следующих функций:1415#### `type PyInterpreterConfig`1617Структура, содержащая большинство параметров для настройки под-интерпретатора. Её значения используются только в [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig) и никогда не изменяются средой выполнения.1819Добавлено в версии 3.12.2021Поля структуры:2223#### `int use_main_obmalloc`2425Если это `0`, то под-интерпретатор будет использовать собственное состояние аллокатора «объектов». В противном случае он будет использовать (разделять) состояние главного интерпретатора.2627Если это `0`, то [`check_multi_interp_extensions`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig.check_multi_interp_extensions) должен быть `1` (ненулевым). Если это `1`, то [`gil`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig.gil) не должен быть [`PyInterpreterConfig_OWN_GIL`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig_OWN_GIL).2829#### `int allow_fork`3031Если это `0`, то среда выполнения не будет поддерживать создание форка процесса в любом потоке, где в данный момент активен под-интерпретатор. В противном случае форк не ограничен.3233Обратите внимание, что модуль [`subprocess`](https://python-all.ru/3.16/library/subprocess.html#module-subprocess) по-прежнему работает, когда форк запрещён.3435#### `int allow_exec`3637Если это `0`, то среда выполнения не будет поддерживать замену текущего процесса через exec (например, [`os.execv()`](https://python-all.ru/3.16/library/os.html#os.execv)) в любом потоке, где в данный момент активен под-интерпретатор. В противном случае exec не ограничен.3839Обратите внимание, что модуль [`subprocess`](https://python-all.ru/3.16/library/subprocess.html#module-subprocess) по-прежнему работает, когда exec запрещён.4041#### `int allow_threads`4243Если это `0`, то модуль [`threading`](https://python-all.ru/3.16/library/threading.html#module-threading) под-интерпретатора не будет создавать потоки. В противном случае потоки разрешены.4445#### `int allow_daemon_threads`4647Если это `0`, то модуль [`threading`](https://python-all.ru/3.16/library/threading.html#module-threading) под-интерпретатора не будет создавать потоки-демоны. В противном случае потоки-демоны разрешены (при условии, что [`allow_threads`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig.allow_threads) не равен нулю).4849#### `int check_multi_interp_extensions`5051Если это `0`, то все модули расширений могут быть импортированы, включая устаревшие модули (с однофазной инициализацией), в любом потоке, где активен под-интерпретатор. В противном случае могут быть импортированы только модули расширений с многофазной инициализацией (см. [**PEP 489**](https://python-all.ru/3.16/c-api/subinterpreters.html)). (См. также [`Py_mod_multiple_interpreters`](https://python-all.ru/3.16/c-api/module.html#c.Py_mod_multiple_interpreters).)5253Это должно быть `1` (ненулевым), если [`use_main_obmalloc`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig.use_main_obmalloc) равно `0`.5455#### `int gil`5657Это определяет режим работы GIL для под-интерпретатора. Он может быть одним из следующих:5859#### `PyInterpreterConfig_DEFAULT_GIL`6061Использовать выбор по умолчанию ([`PyInterpreterConfig_SHARED_GIL`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig_SHARED_GIL)).6263#### `PyInterpreterConfig_SHARED_GIL`6465Использовать (разделять) GIL главного интерпретатора.6667#### `PyInterpreterConfig_OWN_GIL`6869Использовать собственный GIL под-интерпретатора.7071Если это [`PyInterpreterConfig_OWN_GIL`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig_OWN_GIL), то [`PyInterpreterConfig.use_main_obmalloc`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterConfig.use_main_obmalloc) должен быть `0`.7273#### `PyStatus Py_NewInterpreterFromConfig(PyThreadState **tstate_p, const PyInterpreterConfig *config)`7475Создаёт новый под-интерпретатор. Это (почти) полностью независимое окружение для выполнения кода Python. В частности, новый интерпретатор имеет отдельные, независимые версии всех импортированных модулей, включая фундаментальные модули [`builtins`](https://python-all.ru/3.16/library/builtins.html#module-builtins), [`__main__`](https://python-all.ru/3.16/library/__main__.html#module-__main__) и [`sys`](https://python-all.ru/3.16/library/sys.html#module-sys). Таблица загруженных модулей (`sys.modules`) и путь поиска модулей (`sys.path`) также отдельные. В новом окружении нет переменной `sys.argv` . У него есть новые файловые объекты стандартных потоков ввода-вывода `sys.stdin`, `sys.stdout` и `sys.stderr` (однако они ссылаются на те же нижележащие файловые дескрипторы).7677Переданный *config* управляет параметрами, с которыми инициализируется интерпретатор.7879В случае успеха *tstate\_p* будет установлен в первое [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state), созданное в новом под-интерпретаторе. Это состояние потока [присоединено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Обратите внимание, что при этом не создаётся реальный поток; см. обсуждение состояний потока ниже. Если создание нового интерпретатора не удалось, *tstate\_p* устанавливается в `NULL`; исключение не устанавливается, так как состояние исключения хранится в присоединённом состоянии потока, которое может не существовать.8081Как и для всех остальных функций Python/C API, перед вызовом этой функции должно присутствовать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state), но после возврата оно может быть отсоединено. В случае успеха возвращённое состояние потока будет присоединено. Если под-интерпретатор создаётся с собственным [GIL](https://python-all.ru/3.16/glossary.html#term-GIL), то присоединённое состояние потока вызывающего интерпретатора будет отсоединено. Когда функция возвращается, [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state) нового интерпретатора будет присоединено к текущему потоку, а присоединённое состояние потока предыдущего интерпретатора останется отсоединённым.8283Добавлено в версии 3.12.8485Под-интерпретаторы наиболее эффективны при изоляции друг от друга, с ограничением определённой функциональности:8687```c88PyInterpreterConfig config = {89    .use_main_obmalloc = 0,90    .allow_fork = 0,91    .allow_exec = 0,92    .allow_threads = 1,93    .allow_daemon_threads = 0,94    .check_multi_interp_extensions = 1,95    .gil = PyInterpreterConfig_OWN_GIL,96};97PyThreadState *tstate = NULL;98PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);99if (PyStatus_Exception(status)) {100    Py_ExitStatusException(status);101}102```103104Обратите внимание, что config используется только кратковременно и не изменяется. Во время инициализации значения config преобразуются в различные значения [`PyInterpreterState`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterState). Копия config только для чтения может быть сохранена внутри на `PyInterpreterState`.105106Модули расширения совместно используются (под-)интерпретаторами следующим образом:107108- Для модулей, использующих многофазную инициализацию, например [`PyModule_FromDefAndSpec()`](https://python-all.ru/3.16/c-api/module.html#c.PyModule_FromDefAndSpec), для каждого интерпретатора создаётся и инициализируется отдельный объект модуля. Между этими объектами модулей совместно используются только статические и глобальные переменные на уровне C.109- Для модулей, использующих устаревшую [однофазную инициализацию](https://python-all.ru/3.16/c-api/extension-modules.html#single-phase-initialization), например [`PyModule_Create()`](https://python-all.ru/3.16/c-api/module.html#c.PyModule_Create), при первом импорте конкретного расширения оно инициализируется обычным образом, а (поверхностная) копия его словаря модуля сохраняется. Когда то же расширение импортируется другим (под-)интерпретатором, создаётся новый модуль и заполняется содержимым этой копии; функция `init` расширения не вызывается. Объекты в словаре модуля таким образом оказываются совместно используемыми между (под-)интерпретаторами, что может привести к нежелательному поведению (см. [Ошибки и предостережения](https://python-all.ru/3.16/c-api/subinterpreters.html#bugs-and-caveats) ниже).110111  Обратите внимание, что это отличается от ситуации, когда расширение импортируется после полной повторной инициализации интерпретатора вызовом [`Py_FinalizeEx()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_FinalizeEx) и [`Py_Initialize()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_Initialize); в этом случае функция `initmodule` расширения *вызывается* снова. Как и при многофазной инициализации, это означает, что между этими модулями совместно используются только статические и глобальные переменные на уровне C.112113#### `PyThreadState *Py_NewInterpreter(void)`114115*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*116117Создаёт новый под-интерпретатор. По сути, это просто обёртка вокруг [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig) с config, который сохраняет существующее поведение. Результатом является неизолированный под-интерпретатор, который разделяет GIL главного интерпретатора, допускает fork/exec, разрешает фоновые потоки и допускает модули с однофазной инициализацией.118119#### `void Py_EndInterpreter(PyThreadState *tstate)`120121*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*122123Уничтожает (под-)интерпретатор, представленный заданным [состоянием потока](https://python-all.ru/3.16/glossary.html#term-thread-state). Заданное состояние потока должно быть [присоединено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). После возврата вызова не будет присоединённого состояния потока. Все состояния потоков, связанные с этим интерпретатором, уничтожаются.124125[`Py_FinalizeEx()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_FinalizeEx) уничтожит все под-интерпретаторы, которые не были явно уничтожены к этому моменту.126127## Индивидуальный GIL для каждого интерпретатора128129Добавлено в версии 3.12.130131С помощью [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig) можно создать под-интерпретатор, который полностью изолирован от других интерпретаторов, включая собственный GIL. Самое важное преимущество такой изоляции в том, что такой интерпретатор может выполнять код Python без блокировки другими интерпретаторами и не блокируя другие. Таким образом, один процесс Python может по-настоящему использовать несколько ядер CPU при выполнении кода Python. Изоляция также поощряет иной подход к параллелизму, отличный от простого использования потоков. (См. [**PEP 554**](https://python-all.ru/3.16/c-api/subinterpreters.html) и [**PEP 684**](https://python-all.ru/3.16/c-api/subinterpreters.html).)132133Использование изолированного интерпретатора требует бдительности для сохранения этой изоляции. Это особенно означает, что нельзя совместно использовать объекты или изменяемое состояние без гарантий потокобезопасности. Даже объекты, которые в остальном неизменяемы (например, `None`, `(1, 5)`), обычно не могут быть использованы совместно из-за счётчика ссылок. Один простой, но менее эффективный подход – использовать глобальную блокировку при любом использовании некоторого состояния (или объекта). С другой стороны, эффективно неизменяемые объекты (такие как целые числа или строки) можно сделать безопасными, несмотря на их счётчики ссылок, сделав их [бессмертными](https://python-all.ru/3.16/glossary.html#term-immortal). Фактически, это уже сделано для встроенных синглтонов, маленьких целых чисел и ряда других встроенных объектов.134135Если сохранять изоляцию, то будет доступ к настоящим многоядерным вычислениям без осложнений, связанных со свободной многопоточностью. Несоблюдение изоляции приведёт ко всем последствиям свободной многопоточности, включая гонки и трудноотлаживаемые крахи.136137Кроме того, одна из главных проблем использования нескольких изолированных интерпретаторов – как безопасно (не нарушая изоляцию) и эффективно общаться между ними. Среда выполнения и стандартная библиотека пока не предоставляют стандартного подхода для этого. Будущий модуль стандартной библиотеки поможет уменьшить усилия по сохранению изоляции и предоставит эффективные инструменты для обмена (и совместного использования) данными между интерпретаторами.138139## Ошибки и предостережения140141Поскольку под-интерпретаторы (и основной интерпретатор) являются частью одного процесса, изоляция между ними не идеальна – например, используя низкоуровневые файловые операции, такие как [`os.close()`](https://python-all.ru/3.16/library/os.html#os.close), они могут (случайно или злонамеренно) влиять на открытые файлы друг друга. Из-за того, как расширения совместно используются между (под-)интерпретаторами, некоторые расширения могут работать неправильно; это особенно вероятно при использовании однофазной инициализации или (статических) глобальных переменных. Можно вставить объекты, созданные в одном под-интерпретаторе, в пространство имён другого (под-)интерпретатора; этого следует избегать по возможности.142143Следует проявлять особую осторожность, чтобы избежать совместного использования пользовательских функций, методов, экземпляров или классов между под-интерпретаторами, поскольку операции импорта, выполняемые такими объектами, могут повлиять на словарь загруженных модулей не того (под-)интерпретатора. Не менее важно избегать совместного использования объектов, из которых доступны вышеперечисленные.144145Также обратите внимание, что комбинирование этой функциональности с API `PyGILState_*` является деликатным, поскольку эти API предполагают взаимно однозначное соответствие между состояниями потоков Python и потоками уровня ОС, а это предположение нарушается наличием под-интерпретаторов. Настоятельно рекомендуется не переключать под-интерпретаторы между парой соответствующих вызовов [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure) и [`PyGILState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Release). Более того, расширения (такие как [`ctypes`](https://python-all.ru/3.16/library/ctypes.html#module-ctypes)), использующие эти API для вызова кода Python из потоков, созданных не в Python, вероятно, будут работать неправильно при использовании под-интерпретаторов.146147## Высокоуровневые API148149#### `type PyInterpreterState`150151*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) (как непрозрачная структура).*152153Эта структура данных представляет состояние, совместно используемое несколькими взаимодействующими потоками. Потоки, принадлежащие одному интерпретатору, разделяют администрирование модулей и несколько других внутренних элементов. В этой структуре нет открытых членов.154155Потоки, принадлежащие разным интерпретаторам, изначально не разделяют ничего, кроме состояния процесса, такого как доступная память, открытые файловые дескрипторы и т.п. Глобальная блокировка интерпретатора также разделяется всеми потоками, независимо от того, какому интерпретатору они принадлежат.156157Изменено в версии 3.12: [**PEP 684**](https://python-all.ru/3.16/c-api/subinterpreters.html) ввёл возможность [индивидуального GIL для каждого интерпретатора](https://python-all.ru/3.16/c-api/subinterpreters.html#per-interpreter-gil). См. [`Py_NewInterpreterFromConfig()`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.Py_NewInterpreterFromConfig).158159#### `PyInterpreterState *PyInterpreterState_Get(void)`160161*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.9.*162163Получает текущий интерпретатор.164165Вызывает фатальную ошибку, если [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) отсутствует. Функция не может вернуть NULL.166167Добавлено в версии 3.9.168169#### `int64_t PyInterpreterState_GetID(PyInterpreterState *interp)`170171*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.7.*172173Возвращает уникальный идентификатор интерпретатора. Если при этом произошла ошибка, возвращается `-1` и устанавливается исключение.174175Вызывающий должен иметь [прикреплённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).176177Добавлено в версии 3.7.178179#### `PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)`180181*Возвращаемое значение: заимствованная ссылка.*182183*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.8.*184185Возвращает словарь, в котором могут храниться данные, специфичные для интерпретатора. Если эта функция возвращает `NULL`, исключение не было возбуждено, и вызывающий код должен считать, что словарь данных интерпретатора недоступен.186187Это не замена [`PyModule_GetState()`](https://python-all.ru/3.16/c-api/module.html#c.PyModule_GetState), который расширения должны использовать для хранения информации о состоянии интерпретатора.188189Возвращаемый словарь заимствуется из интерпретатора и действителен до завершения работы интерпретатора.190191Добавлено в версии 3.8.192193#### `typedef PyObject *(*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)`194195Тип функции вычисления фрейма.196197Параметр *throwflag* используется методом `throw()` генераторов: если он не равен нулю, обрабатывается текущее исключение.198199Изменено в версии 3.9: Теперь функция принимает параметр *tstate*.200201Изменено в версии 3.11: Параметр *frame* изменился с `PyFrameObject*` на `_PyInterpreterFrame*`.202203#### `_PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp)`204205Возвращает функцию вычисления фрейма.206207См. [**PEP 523**](https://python-all.ru/3.16/c-api/subinterpreters.html) «Добавление API вычисления фрейма в CPython».208209Добавлено в версии 3.9.210211#### `void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)`212213Устанавливает функцию вычисления фрейма.214215См. [**PEP 523**](https://python-all.ru/3.16/c-api/subinterpreters.html) «Добавление API вычисления фрейма в CPython».216217Добавлено в версии 3.9.218219#### `void _PyInterpreterState_SetEvalFrameAllowSpecialization(PyInterpreterState *interp, int allow_specialization)`220221Включает или отключает специализацию, когда установлен собственный вычислитель фреймов.222223Если *allow\_specialization* не равен нулю, адаптивный специализатор продолжит специализировать байт-коды, даже если установлена пользовательская функция вычисления фрейма. Когда *allow\_specialization* равен нулю, установка пользовательского вычислителя отключает специализацию. Стандартный цикл интерпретатора будет продолжать деоптимизацию, пока действует API вычисления фрейма – функция вычисления фрейма должна обрабатывать специализированные опкоды, чтобы воспользоваться этим.224225Добавлено в версии 3.15.226227#### `int _PyInterpreterState_IsSpecializationEnabled(PyInterpreterState *interp)`228229Возвращает ненулевое значение, если для интерпретатора включена адаптивная специализация. Специализация включена, когда не установлена пользовательская функция вычисления фрейма, или когда она установлена с включённым *allow\_specialization*.230231Добавлено в версии 3.15.232233## Низкоуровневые API234235Все следующие функции должны вызываться после [`Py_Initialize()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_Initialize).236237Изменено в версии 3.7: [`Py_Initialize()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_Initialize) теперь инициализирует [GIL](https://python-all.ru/3.16/glossary.html#term-GIL) и устанавливает [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).238239#### `PyInterpreterState *PyInterpreterState_New()`240241*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*242243Создаёт новый объект состояния интерпретатора. [Присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) не требуется, но может опционально существовать, если необходимо сериализовать вызовы этой функции.244245Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `cpython.PyInterpreterState_New` без аргументов.246247#### `void PyInterpreterState_Clear(PyInterpreterState *interp)`248249*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*250251Сбрасывает всю информацию в объекте состояния интерпретатора. Для интерпретатора должно существовать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).252253Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `cpython.PyInterpreterState_Clear` без аргументов.254255#### `void PyInterpreterState_Delete(PyInterpreterState *interp)`256257*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*258259Уничтожает объект состояния интерпретатора. Для целевого интерпретатора **не должно быть** [прикреплённого состояния потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Состояние интерпретатора должно быть сброшено предыдущим вызовом [`PyInterpreterState_Clear()`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterState_Clear).260261## Поддержка расширенной отладки262263Эти функции предназначены только для использования расширенными инструментами отладки.264265#### `PyInterpreterState *PyInterpreterState_Head()`266267Возвращает объект состояния интерпретатора, находящийся в начале списка всех таких объектов.268269#### `PyInterpreterState *PyInterpreterState_Main()`270271Возвращает объект состояния основного интерпретатора.272273#### `PyInterpreterState *PyInterpreterState_Next(PyInterpreterState *interp)`274275Возвращает следующий объект состояния интерпретатора после *interp* из списка всех таких объектов.276277#### `PyThreadState *PyInterpreterState_ThreadHead(PyInterpreterState *interp)`278279Возвращает указатель на первый объект [`PyThreadState`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState) в списке потоков, связанных с интерпретатором *interp*.280281#### `PyThreadState *PyThreadState_Next(PyThreadState *tstate)`282283Возвращает следующий объект состояния потока после *tstate* из списка всех таких объектов, принадлежащих тому же объекту [`PyInterpreterState`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterState).284