Инициализация, финализация и потоки

См. также Конфигурация инициализации Python.

Перед инициализацией Python

В приложении, внедряющем Python, функция Py_Initialize() должна быть вызвана перед использованием любых других функций API Python/C; за исключением нескольких функций и глобальные переменные конфигурации.

Следующие функции можно безопасно вызывать до инициализации Python:

Примечание

Следующие функции не следует вызывать перед Py_Initialize(): Py_EncodeLocale(), Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix(), Py_GetProgramFullPath(), Py_GetPythonHome(), Py_GetProgramName() и PyEval_InitThreads().

Глобальные переменные конфигурации

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

Когда флаг установлен опцией, значение флага — это количество раз, когда опция была установлена. Например, -b устанавливает Py_BytesWarningFlag на 1, а -bb устанавливает Py_BytesWarningFlag на 2.

int Py_BytesWarningFlag

Выдавать предупреждение при сравнении bytes или bytearray с str или bytes с int. Выдать ошибку, если он больше или равен 2.

Устанавливается опцией -b.

int Py_DebugFlag

Включает отладочный вывод парсера (только для экспертов, в зависимости от параметров компиляции).

Устанавливается параметром -d и переменной среды PYTHONDEBUG.

int Py_DontWriteBytecodeFlag

Если установлено ненулевое значение, Python не будет пытаться записывать файлы .pyc при импорте исходных модулей.

Устанавливается параметром -B и переменной среды PYTHONDONTWRITEBYTECODE.

int Py_FrozenFlag

Подавить сообщения об ошибках при вычислении пути поиска модуля в Py_GetPath().

Частный флаг, используемый программами _freeze_importlib и frozenmain.

int Py_HashRandomizationFlag

Устанавливает значение 1, если для переменной среды PYTHONHASHSEED задана непустая строка.

Если флаг не равен нулю, прочитать переменную среды PYTHONHASHSEED, чтобы инициализировать секретное начальное значение хэша.

int Py_IgnoreEnvironmentFlag

Игнорировать все переменные среды PYTHON*, например PYTHONPATH и PYTHONHOME, которые могут быть установлены.

Устанавливается параметрами -E и -I.

int Py_InspectFlag

Когда сценарий передается в качестве первого аргумента или используется опция -c, войдите в интерактивный режим после выполнения сценария или команды, даже если sys.stdin не является терминалом.

Устанавливается параметром -i и переменной среды PYTHONINSPECT.

int Py_InteractiveFlag

Устанавливается опцией -i.

int Py_IsolatedFlag

Запустить Python в изолированном режиме. В изолированном режиме sys.path не содержит ни каталога сценария, ни каталога пакетов сайта Пользователя.

Устанавливается опцией -I.

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

int Py_LegacyWindowsFSEncodingFlag

Если флаг не равен нулю, использовать кодировку mbcs вместо кодировки UTF-8 для кодировки файловой Системы.

Устанавливает значение 1, если для переменной среды PYTHONLEGACYWINDOWSFSENCODING задана непустая строка.

См. PEP 529 для получения более подробной информации.

Доступность: Windows.

int Py_LegacyWindowsStdioFlag

Если флаг не равен нулю, использовать io.FileIO вместо WindowsConsoleIO для стандартных потоков sys.

Устанавливает значение 1, если для переменной среды PYTHONLEGACYWINDOWSSTDIO задана непустая строка.

См. PEP 528 для получения более подробной информации.

Доступность: Windows.

int Py_NoSiteFlag

Отключает импорт модуля site и связанные с ним манипуляции с sys.path, зависящие от сайта. Также отключает данные манипуляции, если site будет явно импортирован позже (вызовите site.main(), если вы хотите, чтобы они запускались).

Устанавливается опцией -S.

int Py_NoUserSiteDirectory

Не добавляйте пользовательский каталог site-packages к sys.path.

Устанавливается параметрами -s и -I и переменной среды PYTHONNOUSERSITE.

int Py_OptimizeFlag

Устанавливается параметром -O и переменной среды PYTHONOPTIMIZE.

int Py_QuietFlag

Не отображать сообщения об авторских правах и версии даже в интерактивном режиме.

Устанавливается опцией -q.

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

int Py_UnbufferedStdioFlag

Принудительно не буферизовать потоки stdout и stderr.

Устанавливается параметром -u и переменной среды PYTHONUNBUFFERED.

int Py_VerboseFlag

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

Устанавливается параметром -v и переменной среды PYTHONVERBOSE.

Инициализация и финализация интерпретатора

void Py_Initialize()

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

Инициализирует таблицу загруженных модулей (sys.modules) и создаёт основные модули builtins, __main__ и sys. Он также инициализирует путь поиска модуля (sys.path). Не ставит sys.argv; использовать для этого PySys_SetArgvEx(). Это не работает при повторном вызове (без первого вызова в Py_FinalizeEx()). Нет возвращаемого значения; если инициализация не удалась, это фатальная ошибка.

Примечание

В Windows изменяет режим консоли с O_TEXT на O_BINARY, что также повлияет на использование консоли, отличной от Python, с использованием среды выполнения C.

void Py_InitializeEx(int initsigs)

Данная функция работает как Py_Initialize(), если initsigs1. Если initsigs — это 0, он пропускает регистрацию инициализации обработчиков сигналов, что может быть полезно при встраивании Python.

int Py_IsInitialized()

Возвращает истину (ненулевое значение), если интерпретатор Python был инициализирован, и ложь (ноль), если нет. После вызова Py_FinalizeEx() это возвращает ложь, пока не будет вызван Py_Initialize() снова.

int Py_FinalizeEx()

Отменяет все инициализации, сделанные Py_Initialize() и последующее использование функций API Python/C, и уничтожает все суб-интерпретаторы (см. Py_NewInterpreter() ниже), которые были созданы и ещё не уничтожены с момента последнего вызова Py_Initialize(). В идеале это освобождает всю память, выделенную интерпретатором Python. Это не работает при повторном вызове (без повторного вызова Py_Initialize()). Обычно возвращаемое значение — 0. Если во время финализации произошли ошибки (очистка буферизованных данных), возвращается -1.

Данная функция предусмотрена по ряду причин. Встраиваемое приложение может захотеть перезапустить Python без перезапуска самого приложения. Приложение, которое загрузило интерпретатор Python из динамически загружаемой библиотеки (или DLL), может захотеть освободить всю память, выделенную Python, перед выгрузкой DLL. Во время поиска утечек памяти в приложении разработчик может захотеть освободить всю память, выделенную Python, перед выходом из приложения.

Ошибки и предостережения: Уничтожение модулей и объектов в модулях производится в случайном порядке; это может привести к сбою деструкторов (методов __del__()), когда они зависят от других объектов (даже функций) или модулей. Динамически загружаемые модули расширения, загруженные Python, не выгружаются. Небольшие объемы памяти, выделенные интерпретатором Python, могут не быть освобождены (если вы обнаружите утечку, сообщить об этом). Память, связанная с циклическими ссылками между объектами, не освобождается. Некоторая память, выделенная модулями расширения, не может быть освобождена. Некоторые расширения могут работать некорректно, если их процедура инициализации вызывается более одного раза; это может произойти, если приложение вызывает Py_Initialize() и Py_FinalizeEx() более одного раза.

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

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

void Py_Finalize()

Это обратно совместимая версия Py_FinalizeEx(), которая игнорирует возвращаемое значение.

Параметры процесса

int Py_SetStandardStreamEncoding(const char *encoding, const char *errors)

Данная функция должна вызываться перед Py_Initialize(), если она вообще вызывается. Он определяет, какую кодировку и обработку ошибок использовать со стандартным вводом-выводом, с тем же значением, что и в str.encode().

Он переопределяет значения PYTHONIOENCODING и позволяет встраивать код для управления кодировкой ввода-вывода, когда переменная среды не работает.

encoding и/или errors могут быть NULL для использования PYTHONIOENCODING и/или значений по умолчанию (в зависимости от других настроек).

Обратите внимание, что sys.stderr всегда использует обработчик ошибок «backslashreplace», независимо от этого (или любого другого) параметра.

Если вызывается Py_FinalizeEx(), эту функцию нужно будет вызвать снова, чтобы повлиять на последующие вызовы Py_Initialize().

Возвращает 0 в случае успеха, ненулевое значение при ошибке (например, вызов после того, как интерпретатор уже был инициализирован).

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

void Py_SetProgramName(const wchar_t *name)

Данная функция должна быть вызвана перед первым вызовом Py_Initialize(), если она вообще вызывается. Он сообщает интерпретатору значение аргумента argv[0] функции main() программы (преобразованное в широкие символы). Это используется Py_GetPath() и некоторыми другими функциями ниже, чтобы найти библиотеки времени выполнения Python относительно исполняемого файла интерпретатора. Значение по умолчанию — 'python'. Аргумент должен указывать на завершающуюся нулем строку широких символов в статическом хранилище, содержимое которой не будет изменяться в течение всего времени выполнения программы. Никакой код в интерпретаторе Python не изменит содержимое этого хранилища.

Использовать Py_DecodeLocale(), чтобы декодировать строку байтов, чтобы получить строку wchar_*.

wchar* Py_GetProgramName()

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

wchar_t* Py_GetPrefix()

Возвращает prefix для установленных файлов, не зависящих от платформы. Это выводится с помощью ряда сложных правил из имени программы, заданного с помощью Py_SetProgramName() и некоторых переменных среды; например, если имя программы — '/usr/local/bin/python', префикс — '/usr/local'. Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Это соответствует переменной prefix в Makefile верхнего уровня и аргументу --prefix сценария configure во время сборки. Значение доступно для кода Python как sys.prefix. Это полезно только в Unix. См. также следующую функцию.

wchar_t* Py_GetExecPrefix()

Возвращает префикс выполняемых для установленных платформозависимых файлов. Это выводится с помощью ряда сложных правил из имени программы, заданного с помощью Py_SetProgramName() и некоторых переменных среды; например, если имя программы — '/usr/local/bin/python', префикс exec — '/usr/local'. Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Это соответствует переменной exec_prefix в Makefile верхнего уровня и аргументу --exec-prefix сценария configure во время сборки. Значение доступно для кода Python как sys.exec_prefix. Это полезно только в Unix.

Справочная информация: префикс exec отличается от префикса, когда файлы, зависящие от платформы (например, исполняемые файлы и разделяемые библиотеки), установлены в другом дереве каталогов. При типичной установке файлы, зависящие от платформы, могут быть установлены в поддереве /usr/local/plat, в то время как независимые от платформы могут быть установлены в /usr/local.

Вообще говоря, платформа представляет собой комбинацию семейств аппаратного и программного обеспечения, например Машины Sparc под управлением операционной системы Solaris 2.x считаются той же платформой, но машины Intel под управлением Solaris 2.x являются другой платформой, а машины Intel под управлением Linux — ещё одной платформой. Различные основные версии одной и той же операционной системы обычно также образуют разные платформы. Другое дело — операционные системы, отличные от Unix; стратегии установки в данных системах настолько различны, что префикс и exec-prefix не имеют смысла и устанавливаются в пустую строку. Обратите внимание, что скомпилированные файлы байт-кода Python не зависят от платформы (но не от версии Python, с помощью которой они были скомпилированы!).

Системные администраторы будут знать, как настроить программы mount или automount для совместного использования /usr/local между платформами, при этом /usr/local/plat будет отдельной файловой системой для каждой платформы.

wchar_t* Py_GetProgramFullPath()

Возвращает полное имя программы исполняемого файла Python; это вычисляется как побочный эффект получения пути поиска модуля по умолчанию из имени программы (установленного выше Py_SetProgramName()). Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Значение доступно для кода Python как sys.executable.

wchar_t* Py_GetPath()

Возвращает путь поиска модуля по умолчанию; это вычисляется из имени программы (установленного выше Py_SetProgramName()) и некоторых переменных среды. Возвращаемая строка состоит из серии имён каталогов, разделенных символом-разделителем, зависящим от платформы. Символ- разделитель — ':' в Unix и Mac OS X, ';' в Windows. Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Список sys.path инициализируется данныем значением при запуске интерпретатора; он может быть (и обычно) изменен позже, чтобы изменить путь поиска для загрузки модулей.

void Py_SetPath(const wchar_t *)

Задаёт путь поиска модуля по умолчанию. Если данная функция вызывается до Py_Initialize(), то Py_GetPath() не будет пытаться вычислить путь поиска по умолчанию, а будет использовать вместо него предоставленный. Это полезно, если Python встроен приложением, которое полностью знает расположение всех модулей. Компоненты пути должны быть разделены символом- разделителем, зависящим от платформы, которым является ':' в Unix и Mac OS X, ';' в Windows.

Это также приводит к тому, что sys.executable устанавливается на полный путь к программе (см. Py_GetProgramFullPath()), а sys.prefix и sys.exec_prefix остаются пустыми. При необходимости вызывающий абонент может изменить их после вызова Py_Initialize().

Использовать Py_DecodeLocale(), чтобы декодировать строку байтов, чтобы получить строку wchar_*.

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

Изменено в версии 3.8: Теперь для sys.executable вместо имени программы используется полный путь к программе.

const char* Py_GetVersion()

Возвращает версию этого интерпретатора Python. Это строка, которая выглядит примерно так:

"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"

Первое слово (до первого пробела) — это текущая версия Python; первые три символа — это основная и дополнительная версия, разделенные точкой. Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Значение доступно для кода Python как sys.version.

const char* Py_GetPlatform()

Возвращает идентификатор платформы для текущей платформы. В Unix оно формируется из «официального» названия операционной системы, преобразованного в нижний регистр, за которым следует номер основной версии; например, для Solaris 2.x, также известного как SunOS 5.x, значение будет 'sunos5'. В Mac OS X это 'darwin'. В Windows это 'win'. Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Значение доступно для кода Python как sys.platform.

const char* Py_GetCopyright()

Например, возвращает официальную строку авторских прав для текущей версии Python

'Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam'

Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Значение доступно для кода Python как sys.copyright.

const char* Py_GetCompiler()

Возвращает указание компилятора, используемого для сборки текущей версии Python, например, в квадратных скобках:

"[GCC 2.7.2.2]"

Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Значение доступно для кода Python как часть переменной sys.version.

const char* Py_GetBuildInfo()

Например, возвращает информацию о порядковом номере, дате и времени сборки текущего экземпляра интерпретатора Python:

"#67, Aug  1 1997, 22:34:28"

Возвращенная строка указывает в статическое хранилище; вызывающий не должен изменять его значение. Значение доступно для кода Python как часть переменной sys.version.

void PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)

Устанавливает sys.argv на основе argc и argv. Данные параметры аналогичны тем, которые передаются функции main() программы, с той разницей, что первая запись должна относиться к исполняемому файлу сценария, а не к исполняемому файлу, на котором размещен интерпретатор Python. Если сценарий, который будет запускаться, отсутствует, первая запись в argv может быть пустой строкой. Если этой функции не удается инициализировать sys.argv, фатальное состояние сигнализируется с помощью Py_FatalError().

Если updatepath равен нулю, это все, что делает функция. Если updatepath не равно нулю, функция также изменяет sys.path согласно следующему алгоритму:

  • Если имя существующего сценария передается в argv[0], абсолютный путь к каталогу, в котором находится сценарий, добавляется к sys.path.
  • В противном случае (т. е., если argc — это 0 или argv[0] не указывает на существующее имя файла), перед sys.path добавляется пустая строка, что аналогично добавлению текущего рабочего каталога (".").

Использовать Py_DecodeLocale(), чтобы декодировать строку байтов, чтобы получить строку wchar_*.

Примечание

Рекомендуется, чтобы приложения, встраивающие интерпретатор Python для целей, отличных от выполнения одного сценария, передавали 0 как updatepath и при необходимости обновляли sys.path. См. CVE-2008-5983.

В версиях до 3.1.3 вы можете добиться того же эффекта, вручную выдвинув первый элемент sys.path после вызова PySys_SetArgv(), например, используя:

PyRun_SimpleString("import sys; sys.path.pop(0)\n");

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

void PySys_SetArgv(int argc, wchar_t **argv)

Данная функция работает как PySys_SetArgvEx() с updatepath, установленным на 1, если интерпретатор python не был запущен с -I.

Использовать Py_DecodeLocale(), чтобы декодировать строку байтов, чтобы получить строку wchar_*.

Изменено в версии 3.4: The updatepath value depends on -I.

void Py_SetPythonHome(const wchar_t *home)

Устанавливает «домашний» каталог по умолчанию, т. е. расположение стандартных библиотек Python. См. PYTHONHOME, чтобы узнать значение строки аргумента.

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

Использовать Py_DecodeLocale(), чтобы декодировать строку байтов, чтобы получить строку wchar_*.

w_char* Py_GetPythonHome()

Возвращает значение по умолчанию «home», т. е. значение, установленное предыдущим вызовом Py_SetPythonHome(), или значение переменной среды PYTHONHOME, если она установлена.

Состояние потока и глобальная блокировка интерпретатора

Интерпретатор Python не является полностью потокобезопасным. Для поддержки многопоточных программ Python существует глобальная блокировка, называемая глобальная блокировка интерпретатора или GIL, которая должна удерживаться текущим потоком, прежде чем он сможет безопасно обращаться к объектам Python. Без блокировки даже самые простые операции могут вызвать проблемы в многопоточной программе: например, когда два потока одновременно увеличивают счётчик ссылок одного и того же объекта, счётчик ссылок может увеличиваться только один раз, а не дважды.

Следовательно, существует правило, согласно которому только поток, получивший GIL, может работать с объектами Python или вызывать функции API Python/C. Чтобы имитировать параллелизм выполнения, интерпретатор регулярно пытается переключить потоки (см. sys.setswitchinterval()). Блокировка также снимается вокруг потенциально блокирующих операций ввода-вывода, таких как чтение или запись файла, так что другие потоки Python могут работать в это время.

Интерпретатор Python хранит некоторую бухгалтерскую информацию, относящуюся к потоку, внутри структуры данных под названием PyThreadState. Также есть одна глобальная переменная, указывающая на текущий PyThreadState: её можно получить с помощью PyThreadState_Get().

Освобождение GIL от кода расширения

У большей части кода расширения, управляющего GIL, есть следующая простая структура:

Save the thread state in a local variable.
Release the global interpreter lock.
... Do some blocking I/O operation ...
Reacquire the global interpreter lock.
Restore the thread state from the local variable.

Это настолько распространено, что существует пара макросов для его упрощения:

Py_BEGIN_ALLOW_THREADS
... Do some blocking I/O operation ...
Py_END_ALLOW_THREADS

Макрос Py_BEGIN_ALLOW_THREADS открывает новый блок и объявляет скрытую локальную переменную; макрос Py_END_ALLOW_THREADS закрывает блок.

Блок выше расширяется до следующего кода:

PyThreadState *_save;

_save = PyEval_SaveThread();
... Do some blocking I/O operation ...
PyEval_RestoreThread(_save);

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

Примечание

Вызов системных функций ввода-вывода является наиболее распространенным вариантом использования для релиза GIL, но он также может быть полезен перед вызовом длительных вычислений, которым не требуется доступ к объектам Python, таким как сжатие или криптографические функции, работающие с буферами памяти. Например, стандартные модули zlib и hashlib освобождают GIL при сжатии или хешировании данных.

Потоки, созданные не на Python

Когда потоки создаются с использованием выделенных API-интерфейсов Python (таких как модуль threading), с ними автоматически связывается состояние потока, и поэтому приведенный выше код является правильным. Однако, когда потоки создаются из C (например, сторонней библиотекой с собственным управлением потоками), они не содержат ни GIL, ни структуры состояния потока для них.

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

Функции PyGILState_Ensure() и PyGILState_Release() выполняют все вышеперечисленное автоматически. Типичная идиома для вызова Python из потока C:

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

/* Выполнить действия Python здесь. */
result = CallSomeFunction();
/* вычислить результат или обработать исключение */

/* Отпустить нить. После этого API Python не допускается. */
PyGILState_Release(gstate);

Обратите внимание, что функции PyGILState_*() предполагают, что существует только один глобальный интерпретатор (автоматически создаётся Py_Initialize()). Python поддерживает создание дополнительных интерпретаторов (с использованием Py_NewInterpreter()), но смешивание нескольких интерпретаторов и API PyGILState_*() не поддерживается.

Предупреждения относительно fork()

Ещё одна важная вещь, на которую следует обратить внимание, — это их поведение при вызове C fork(). В большинстве систем с fork() после того, как процесс разветвляется, будет существовать только поток, который запустил вилку. Это оказывает влияние как на то, как должны обрабатываться блокировки, так и на все сохраненное состояние в среде выполнения CPython.

Тот факт, что остается только «текущий» поток, означает, что любые блокировки, удерживаемые другими потоками, никогда не будут сняты. Python решает эту проблему для os.fork(), получая блокировки, которые он использует внутри до вилки, и освобождая их после этого. Кроме того, он сбрасывает любой Объекты блокировки в дочернем элементе. При расширении или внедрении Python невозможно сообщить Python о дополнительных (не связанных с Python) блокировках, которые необходимо установить до или сбросить после вилки. Для достижения той же цели необходимо использовать средства ОС, такие как pthread_atfork(). Кроме того, при расширении или встраивании Python вызов fork() напрямую, а не через os.fork() (и возвращение или вызов Python) может привести к тупиковой ситуации из-за того, что одна из внутренних блокировок Python удерживается потоком, который перестает функционировать после вилки. PyOS_AfterFork_Child() пытается сбросить необходимые блокировки, но не всегда может.

Тот факт, что все другие потоки удаляются, также означает, что состояние времени выполнения CPython должно быть очищено должным образом, что и делает os.fork(). Это означает завершение всех остальных объектов PyThreadState, принадлежащих текущему интерпретатору, и всех других объектов PyInterpreterState. Из-за этого и из-за особого характера «главный» интерпретатор, fork() следует вызывать только в «основном» потоке этого интерпретатора, где изначально была инициализирована глобальная среда выполнения CPython. Единственное исключение — если сразу после этого будет вызван exec().

API высокого уровня

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

PyInterpreterState

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

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

PyThreadState

Cтруктура данных представляет состояние одного потока. Единственным публичным элементом данных является interp (PyInterpreterState *), который указывает на состояние интерпретатора этого потока.

void PyEval_InitThreads()

Инициализировать и получить глобальную блокировку интерпретатора. Его следует вызывать в основном потоке перед созданием второго потока или подключением к любым другим операциям потока, таким как PyEval_ReleaseThread(tstate). Это не нужно перед вызовом в PyEval_SaveThread() или PyEval_RestoreThread().

При повторном вызове это не работает.

Изменено в версии 3.7: Данная функция теперь вызывается: c:func:Py_Initialize(), поэтому вам больше не нужно вызывать её самостоятельно.

Изменено в версии 3.2: Эту функцию нельзя вызвать раньше: c:func:Py_Initialize().

int PyEval_ThreadsInitialized()

Возвращает ненулевое значение, если был вызван PyEval_InitThreads(). Данная функция может быть вызвана без удержания GIL и, следовательно, может использоваться, чтобы избежать вызовов API-интерфейса блокировки при работе в однопоточном режиме.

Изменено в версии 3.7: Теперь GIL инициализирован: c:func:Py_Initialize().

PyThreadState* PyEval_SaveThread()

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

void PyEval_RestoreThread(PyThreadState *tstate)

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

Примечание

Вызов этой функции из потока, когда среда выполнения завершает работу, завершит поток, даже если поток не был создан Python. Вы можете использовать _Py_IsFinalizing() или sys.is_finalizing(), чтобы проверить, находится ли интерпретатор в процессе завершения перед вызовом этой функции, чтобы избежать нежелательного завершения.

PyThreadState* PyThreadState_Get()

Возвращает текущее состояние потока. Необходимо удерживать глобальную блокировку интерпретатора. Когда текущее состояние потока — NULL, происходит фатальная ошибка (так что вызывающему абоненту не нужно проверять NULL).

PyThreadState* PyThreadState_Swap(PyThreadState *tstate)

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

Следующие функции используют локальное хранилище потока и несовместимы с субинтерпретаторами:

PyGILState_STATE PyGILState_Ensure()

Убедитесь, что текущий поток готов вызвать Python C API независимо от текущего состояния Python или глобальной блокировки интерпретатора. Это может вызываться потоком столько раз, сколько требуется, пока каждый вызов сопоставляется с вызовом PyGILState_Release(). Как правило, между вызовами PyGILState_Ensure() и PyGILState_Release() могут использоваться другие API-интерфейсы, связанные с потоками, при условии, что состояние потока восстановлено до своего предыдущего состояния до Release(). Например, допустимо обычное использование макросов Py_BEGIN_ALLOW_THREADS и Py_END_ALLOW_THREADS.

Возвращаемое значение представляет собой непрозрачный «дескриптор» состояния потока при вызове PyGILState_Ensure(), и его необходимо передать в PyGILState_Release(), чтобы обеспечить сохранение Python в том же состоянии. Несмотря на то, что рекурсивные вызовы разрешены, данные дескрипторы не являются общими — каждый уникальный вызов PyGILState_Ensure() должен сохранять дескриптор для своего вызова PyGILState_Release().

Когда функция вернётся, текущий поток будет содержать GIL и иметь возможность вызывать произвольный код Python. Неудача — это фатальная ошибка.

Примечание

Вызов этой функции из потока, когда среда выполнения завершает работу, завершит поток, даже если поток не был создан Python. Вы можете использовать _Py_IsFinalizing() или sys.is_finalizing(), чтобы проверить, находится ли интерпретатор в процессе завершения перед вызовом этой функции, чтобы избежать нежелательного завершения.

void PyGILState_Release(PyGILState_STATE)

Освободить все ранее приобретенные ресурсы. После этого вызова состояние Python будет таким же, как и до соответствующего вызова PyGILState_Ensure() (но, как правило, это состояние будет неизвестно вызывающему, отсюда и использование GILState API).

Каждый вызов PyGILState_Ensure() должен сопровождаться вызовом PyGILState_Release() в том же потоке.

PyThreadState* PyGILState_GetThisThreadState()

Получить текущее состояние потока для этого потока. Может возвращает NULL, если в текущем потоке не использовался API GILState. Обратите внимание, что у основного потока всегда есть такое состояние потока, даже если в основном потоке не выполнялся вызов автоматического состояния потока. В основном это вспомогательная/диагностическая функция.

int PyGILState_Check()

Возвращает 1, если текущий поток содержит GIL, и 0 в противном случае. Данная функция может быть вызвана из любого потока в любое время. Только если он инициализировал состояние потока Python и в настоящее время удерживает GIL, он вернёт 1. В основном это вспомогательная/диагностическая функция. Это может быть полезно, например, в контекстах обратного вызова или функциях выделения памяти, когда знание того, что GIL заблокирован, может позволить вызывающей стороне выполнять конфиденциальные действия или иным образом вести себя по-другому.

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

Следующие макросы обычно используются без точки с запятой в конце; посмотрите пример использования в дистрибутиве исходного кода Python.

Py_BEGIN_ALLOW_THREADS

Данный макрос расширяется до { PyThreadState *_save; _save = PyEval_SaveThread();. Обратите внимание, что он содержит открывающую скобку; он должен соответствовать следующему макросу Py_END_ALLOW_THREADS. См. выше для дальнейшего обсуждения данного макроса.

Py_END_ALLOW_THREADS

Данный макрос расширяется до PyEval_RestoreThread(_save); }. Обратите внимание, что он содержит закрывающую скобку; он должен соответствовать более раннему макросу Py_BEGIN_ALLOW_THREADS. См. выше для дальнейшего обсуждения данного макроса.

Py_BLOCK_THREADS

Данный макрос расширяется до PyEval_RestoreThread(_save);: он эквивалентен Py_END_ALLOW_THREADS без закрывающей фигурной скобки.

Py_UNBLOCK_THREADS

Данный макрос расширяется до _save = PyEval_SaveThread();: он эквивалентен Py_BEGIN_ALLOW_THREADS без открывающей скобки и объявления переменной.

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

Все следующие функции должны вызываться после Py_Initialize().

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

PyInterpreterState* PyInterpreterState_New()

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

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

void PyInterpreterState_Clear(PyInterpreterState *interp)

Сбросить всю информацию в объекте состояния интерпретатора. Необходимо удерживать глобальную блокировку интерпретатора.

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

void PyInterpreterState_Delete(PyInterpreterState *interp)

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

PyThreadState* PyThreadState_New(PyInterpreterState *interp)

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

void PyThreadState_Clear(PyThreadState *tstate)

Сбросить всю информацию в объекте состояния потока. Необходимо удерживать глобальную блокировку интерпретатора.

void PyThreadState_Delete(PyThreadState *tstate)

Уничтожить объект состояния потока. Глобальную блокировку интерпретатора удерживать не нужно. Состояние потока должно быть сброшено предыдущим вызовом PyThreadState_Clear().

PY_INT64_T PyInterpreterState_GetID(PyInterpreterState *interp)

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

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

PyObject* PyInterpreterState_GetDict(PyInterpreterState *interp)

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

Это не замена: c:func:PyModule_GetState(), которые расширения должны использовать для хранения информации о состоянии, специфичной для интерпретатора.

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

PyObject* PyThreadState_GetDict()
Return value: Borrowed reference.

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

int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)

Асинхронно вызывать исключение в потоке. Аргумент id — это идентификатор целевого потока; exc — это вызываемый объект исключения. Данная функция не крадет никаких ссылок на exc. Чтобы предотвратить наивное неправильное использование, вы должны написать собственное расширение C для вызова этого. Должен быть вызван с удержанием GIL. Возвращает количество измененных состояний потока; обычно это единица, но будет равно нулю, если идентификатор потока не найден. Если excNULL, ожидающее исключение (если есть) для потока очищается. Здесь нет исключений.

Изменено в версии 3.7: Тип параметра id изменён с long на unsigned long.

void PyEval_AcquireThread(PyThreadState *tstate)

Получить глобальную блокировку интерпретатора и устанавливает текущее состояние потока на tstate, которое не должно быть NULL. Блокировка должна быть создана ранее. Если данный поток уже есть блокировка, наступает тупик.

Примечание

Вызов этой функции из потока, когда среда выполнения завершает работу, завершит поток, даже если поток не был создан Python. Вы можете использовать _Py_IsFinalizing() или sys.is_finalizing(), чтобы проверить, находится ли интерпретатор в процессе завершения перед вызовом этой функции, чтобы избежать нежелательного завершения.

Изменено в версии 3.8: Обновлено, чтобы соответствовать PyEval_RestoreThread(), Py_END_ALLOW_THREADS() и PyGILState_Ensure(), а также завершить текущий поток, если он вызывается во время завершения интерпретатора.

PyEval_RestoreThread() — это функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).

void PyEval_ReleaseThread(PyThreadState *tstate)

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

PyEval_SaveThread() — это функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).

void PyEval_AcquireLock()

Получает глобальную блокировку интерпретатора. Блокировка должна быть создана ранее. Если у данного потока уже есть блокировка, происходит тупик.

Не рекомендуется, начиная с версии 3.2: Данная функция не обновляет текущее состояние потока. Вместо этого использовать PyEval_RestoreThread() или PyEval_AcquireThread().

Примечание

Вызов этой функции из потока, когда среда выполнения завершает работу, завершит поток, даже если поток не был создан Python. Вы можете использовать _Py_IsFinalizing() или sys.is_finalizing(), чтобы проверить, находится ли интерпретатор в процессе завершения перед вызовом этой функции, чтобы избежать нежелательного завершения.

Изменено в версии 3.8: Обновлено, чтобы соответствовать PyEval_RestoreThread(), Py_END_ALLOW_THREADS() и PyGILState_Ensure(), а также завершить текущий поток, если он вызывается во время завершения интерпретатора.

void PyEval_ReleaseLock()

Снять глобальную блокировку интерпретатора. Блокировка должена быть создана ранее.

Не рекомендуется, начиная с версии 3.2: Данная функция не обновляет текущее состояние потока. Вместо этого использовать PyEval_SaveThread() или PyEval_ReleaseThread().

Поддержка субинтерпретатора

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

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

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

PyThreadState* Py_NewInterpreter()

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

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

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

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

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

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

void Py_EndInterpreter(PyThreadState *tstate)

Уничтожить (суб)интерпретатор, представленный данным состоянием потока. Данное состояние потока должно быть текущим состоянием потока. См. обсуждение состояний потоков ниже. Когда вызов возвращается, текущее состояние потока — NULL. Все состояния потока, связанные с данныем интерпретатором, уничтожаются. (Глобальная блокировка интерпретатора должна удерживаться перед вызовом этой функции и все ещё удерживаться при её возврате.) Py_FinalizeEx() уничтожит все субинтерпретаторы, которые не были явно уничтожены в данный момент.

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

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

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

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

Асинхронные уведомления

Предоставляется механизм для отправки асинхронных уведомлений в основной поток интерпретатора. Данные уведомления принимают форму указателя на функцию и аргумента недействительного указателя.

int Py_AddPendingCall(int (*func)(void *), void *arg)

Запланировать вызов функции из основного потока интерпретатора. В случае успеха возвращается 0, а func ставится в очередь для вызова в основном потоке. В случае сбоя возвращается -1 без установки каких-либо исключений.

При успешной постановке в очередь func будет eventually, вызываемым из основного потока интерпретатора с аргументом arg. Он будет вызываться асинхронно по отношению к нормально работающему коду Python, но при соблюдении обоих данных условий:

func должен возвращать 0 в случае успеха или -1 в случае неудачи с установленным исключением. func не будет прервана для рекурсивного выполнения другого асинхронного уведомления, но его все равно можно прервать для переключения потоков, если снята глобальная блокировка интерпретатора.

Для запуска этой функции не требуется текущее состояние потока и глобальная блокировка интерпретатора.

Предупреждение

Это низкоуровневая функция, полезная только в очень особых случаях. Нет гарантии, что func будет вызван как можно быстрее. Если основной поток занят выполнением системного вызова, func не будет вызываться до возврата из системного вызова. Данная функция обычно не подходит для вызова кода Python из произвольных потоков C. Вместо этого использовать PyGILState API.

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

Профилирование и отслеживание

Интерпретатор Python обеспечивает некоторую низкоуровневую поддержку для подключения средств профилирования и трассировки выполнения. Они используются для инструментов профилирования, отладки и анализа покрытия.

Данный C интерфейс позволяет коду профилирования или трассировки избежать накладных расходов на вызовы через вызываемые объекты уровня Python, вместо этого выполняя прямой вызов C функции. Существенные атрибуты объекта не изменились; интерфейс позволяет устанавливать функции трассировки для каждого потока, а основные события, сообщаемые функции трассировки, такие же, как сообщалось функциям трассировки уровня Python в предыдущих версиях.

int (*Py_tracefunc)(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)

Тип функции трассировки, зарегистрированный с помощью PyEval_SetProfile() и PyEval_SetTrace(). Первым параметром является объект, переданный функции регистрации как obj, frame является объектом фреймом, к которому относится событие, what является одной из констант PyTrace_CALL, PyTrace_EXCEPTION, PyTrace_LINE, PyTrace_RETURN, PyTrace_C_CALL, PyTrace_C_EXCEPTION, PyTrace_C_RETURN или PyTrace_OPCODE и arg зависит от значения what:

Значение what Значение arg
PyTrace_CALL Всегда Py_None.
PyTrace_EXCEPTION Информация об исключении, возвращаемая sys.exc_info().
PyTrace_LINE Всегда Py_None.
PyTrace_RETURN Значение, возвращаемое вызывающему, или NULL если вызвано исключение.
PyTrace_C_CALL Вызываемый функциональный объект.
PyTrace_C_EXCEPTION Вызываемый функциональный объект.
PyTrace_C_RETURN Вызываемый функциональный объект.
PyTrace_OPCODE Всегда Py_None.
int PyTrace_CALL

Значение параметра what для функции Py_tracefunc, когда сообщается о новом вызове функции или метода или о новой записи в генератор. Обратите внимание, что о создании итератора для функции генератора не сообщается, поскольку в соответствующем фрейме отсутствует передача управления байт-коду Python.

int PyTrace_EXCEPTION

Значение параметра what для функции Py_tracefunc при возникновении исключения. Функция обратного вызова вызывается с данныем значением для what, когда после обработки любого байт-кода, после чего исключение устанавливается в выполняемом фрейме. Результатом этого является то, что, поскольку распространение исключения вызывает раскручивание стека Python, обратный вызов вызывается при возврате к каждому фрейму по мере распространения исключения. Данные события получают только функции трассировки; они не нужны профилировщику.

int PyTrace_LINE

Значение, переданное в качестве параметра what функции Py_tracefunc (но не функции профилирования) при сообщении события номера строки. Его можно отключить для фрейма, установив f_trace_lines на 0 для этого фрейма.

int PyTrace_RETURN

Значение параметра what для функций Py_tracefunc, когда вызов собирается возвращается.

int PyTrace_C_CALL

Значение параметра what для Py_tracefunc функции, когда функция C. собирается быть вызвана.

int PyTrace_C_EXCEPTION

Значение параметра what для функций Py_tracefunc, когда функция C вызвала исключение.

int PyTrace_C_RETURN

Значение параметра what для функций Py_tracefunc, когда функция C вернулась.

int PyTrace_OPCODE

Значение параметра what для функций Py_tracefunc (но не функций профилирования) при приближении к выполнению нового кода операции. Это событие не генерируется по умолчанию: оно должно быть явно запрошено путем установки f_trace_opcodes на 1 в фрейме.

void PyEval_SetProfile(Py_tracefunc func, PyObject *obj)

Устанавливает для функции профилировщика значение func. Параметр obj передается функции в качестве её первого параметра и может быть любым объектом Python или NULL. Если функция профиля должна поддерживать состояние, использование другого значения для obj для каждого потока обеспечивает удобное и безопасное для потоков место для его сохранения. Функция профиля вызывается для всех отслеживаемых событий, кроме PyTrace_LINE, PyTrace_OPCODE и PyTrace_EXCEPTION.

void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)

Устанавливает для функции отслеживания значение func. Это похоже на PyEval_SetProfile(), за исключением того, что функция трассировки действительно принимает события номеров строк и события для каждого кода операции, но не получает никаких событий, связанных с вызываемыми объектами функции C. Любая функция трассировки, зарегистрированная с использованием PyEval_SetTrace(), не получит PyTrace_C_CALL, PyTrace_C_EXCEPTION или PyTrace_C_RETURN в качестве значения для параметра what.

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

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

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.

Поддержка локального хранилища потоков

Интерпретатор Python обеспечивает низкоуровневую поддержку для локального хранилища потоков (TLS), который обертывает базовую собственную реализацию TLS для поддержки API локального хранилища потоков на уровне Python (threading.local). API-интерфейсы CPython уровня C аналогичны API- интерфейсам pthreads и Windows: использовать ключ потока и функции, чтобы связать значение void* для каждого потока.

GIL не требует удержания при вызове данных функций; они поставляют свои собственные блокировки.

Обратите внимание, что Python.h не включает объявление TLS API, вам необходимо включить pythread.h, чтобы использовать локальное хранилище потока.

Примечание

Ни одна из данных функций API не обрабатывает управление памятью от имени значений void*. Вам нужно выделить и освободить их самостоятельно. Если значения void* совпадают с PyObject*, данные функции также не выполняют для них операций refcount.

API хранилища для потоков (TSS)

TSS API вводится, чтобы заменить использование существующего TLS API в интерпретаторе CPython. Данный API использует новый тип Py_tss_t вместо int для представления ключей потоков.

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

См.также

«Новый C-API для локального хранилища потоков в CPython» (PEP 539)

Py_tss_t

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

Если Py_LIMITED_API не определён, разрешено статическое выделение этого типа с помощью Py_tss_NEEDS_INIT.

Py_tss_NEEDS_INIT

Данный макрос расширяется до инициализатора для переменных Py_tss_t. Обратите внимание, что данный макрос не будет определён с Py_LIMITED_API.

Динамическое размещение

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

Py_tss_t* PyThread_tss_alloc()

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

void PyThread_tss_free(Py_tss_t *key)

Освободить данный key, выделенный PyThread_tss_alloc(), после первого вызова PyThread_tss_delete(), чтобы убедиться, что все связанные локальные переменные потока не назначены. Это не работает, если у аргумента key значение NULL.

Примечание

Освободившийся ключ становится висящим указателем, вы должны сбросить ключ на NULL.

Методы

Параметр key данных функций не должен быть NULL. Более того, поведение PyThread_tss_set() и PyThread_tss_get() не определёно, если данный Py_tss_t не был инициализирован PyThread_tss_create().

int PyThread_tss_is_created(Py_tss_t *key)

Возвращает ненулевое значение, если данный Py_tss_t был инициализирован PyThread_tss_create().

int PyThread_tss_create(Py_tss_t *key)

Возвращает нулевое значение при успешной инициализации ключа TSS. Поведение не определёно, если значение, на которое указывает аргумент key, не инициализировано Py_tss_NEEDS_INIT. Эту функцию можно вызывать несколько раз для одного и того же ключа — вызов её для уже инициализированного ключа не выполняется и немедленно возвращает успех.

void PyThread_tss_delete(Py_tss_t *key)

Уничтожить ключ TSS, чтобы забыть значения, связанные с ключом во всех потоках, и изменить состояние инициализации ключа на неинициализированное. Уничтоженный ключ может быть снова инициализирован PyThread_tss_create(). Эту функцию можно многократно вызывать для одного и того же ключа — вызывать её для уже уничтоженного ключа нельзя.

int PyThread_tss_set(Py_tss_t *key, void *value)

Возвращает нулевое значение, чтобы указать успешное связывание значения void* с ключом TSS в текущем потоке. У каждого потока есть отдельное отображение ключа на значение void*.

void* PyThread_tss_get(Py_tss_t *key)

Возвращает значение void*, связанное с ключом TSS в текущем потоке. Это возвращает NULL, если с ключом в текущем потоке не связано никакого значения.

API локального хранилища потоков (TLS)

Не рекомендуется, начиная с версии 3.7: Данный API заменён API хранилища для потоков (TSS, Thread Specific Storage).

Примечание

Данная версия API не поддерживает платформы, на которых собственный ключ TLS определён таким образом, что его нельзя безопасно преобразовать в int. На таких платформах PyThread_create_key() немедленно вернётся со статусом сбоя, и все другие функции TLS на таких платформах не будут работать.

Из-за проблемы совместимости, указанной выше, эту версию API не следует использовать в новом коде.

int PyThread_create_key()
void PyThread_delete_key(int key)
int PyThread_set_key_value(int key, void *value)
void* PyThread_get_key_value(int key)
void PyThread_delete_key_value(int key)
void PyThread_ReInitTLS()