Spec-Zone.ru › Python 3.8

Инициализация, завершение и потоки

См. также Настройка инициализации Python.

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

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

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

  • Функции конфигурации:

    • PyImport_AppendInittab()
    • PyImport_ExtendInittab()
    • PyInitFrozenExtensions()
    • PyMem_SetAllocator()
    • PyMem_SetupDebugHooks()
    • PyObject_SetArenaAllocator()
    • Py_SetPath()
    • Py_SetProgramName()
    • Py_SetPythonHome()
    • Py_SetStandardStreamEncoding()
    • PySys_AddWarnOption()
    • PySys_AddXOption()
    • PySys_ResetWarnOptions()
  • Информационные функции:

    • Py_IsInitialized()
    • PyMem_GetAllocator()
    • PyObject_GetArenaAllocator()
    • Py_GetBuildInfo()
    • Py_GetCompiler()
    • Py_GetCopyright()
    • Py_GetPlatform()
    • Py_GetVersion()
  • Утилиты:

    • Py_DecodeLocale()
  • Аллокаторы памяти:

    • PyMem_RawMalloc()
    • PyMem_RawRealloc()
    • PyMem_RawCalloc()
    • PyMem_RawFree()

Примечание

Следующие функции не следует вызывать до 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 не содержит ни директорию скрипта, ни директорию site-packages пользователя.

Устанавливается опцией -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

Не добавлять user site-packages directory в 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.

END_OF_DOCUMENT_MARKER

Инициализация и завершение работы интерпретатора

void Py_Initialize()

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

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

Примечание

В Windows, изменяет режим консоли с O_TEXT на O_BINARY, что также повлияет на использование консоли не связанными с Python программами, использующими C Runtime.

void Py_InitializeEx(int initsigs)

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

int Py_IsInitialized()

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

int Py_FinalizeEx()

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

Эта функция предоставляется по нескольким причинам. Приложение, которое включает интерпретатор Python, может захотеть перезапустить 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 runtime относительно исполняемого файла интерпретатора. Значение по умолчанию — 'python'. Аргумент должен указывать на строку с нулевым завершением, состоящую из широких символов, хранящуюся в статическом хранилище, содержимое которого не изменяется на протяжении всего выполнения программы. Ни один код в интерпретаторе Python не изменит содержимое этого хранилища.

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

wchar* Py_GetProgramName()

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

wchar_t* Py_GetPrefix()

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

wchar_t* Py_GetExecPrefix()

Возвращает exec-префикс для установок файлов, зависимых от платформы. Он выводится по ряду сложных правил из имени программы, заданного с помощью 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-префикс бессмысленны и установлены в пустую строку. Обратите внимание, что скомпилированные файлы байткода 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_*.

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

Изменено в версии 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: Значение updatepath зависит от -I.

void Py_SetPythonHome(const wchar_t *home)

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

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

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

w_char* Py_GetPythonHome()

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

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

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

Поэтому существует правило, что только поток, получивший GIL, может выполнять операции с объектами Python или вызывать функции Python/C API. Для эмуляции одновременного выполнения интерпретатор регулярно пытается переключать потоки (см. 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();

/* Perform Python actions here. */
result = CallSomeFunction();
/* evaluate result or handle exception */

/* Release the thread. No Python API allowed beyond this point. */
PyGILState_Release(gstate);

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

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

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

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

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

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

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

PyInterpreterState

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

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

PyThreadState

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

void PyEval_InitThreads()

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

При повторном вызове эта функция является пустой операцией.

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

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

int PyEval_ThreadsInitialized()

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

Изменено в версии 3.7: Теперь блокировка GIL инициализируется функцией 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()

Обеспечивает, что текущий поток готов к вызову API Python C независимо от текущего состояния Python или глобальной блокировки интерпретатора. Этот вызов можно повторять любое количество раз в потоке, при условии, что каждый вызов сопровождается вызовом PyGILState_Release(). В общем случае, другие API, связанные с потоками, могут использоваться между вызовами PyGILState_Ensure() и PyGILState_Release(), при условии, что состояние потока будет восстановлено в исходное состояние перед вызовом 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() (но, как правило, это состояние неизвестно вызывающей стороне, отсюда и использование API GILState).

Каждый вызов 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 без открывающей фигурной скобки и объявления переменной.

END_OF_DOCUMENT_MARKER

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

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

Изменено в версии 3.7: 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, исключение не было возбуждено, и вызывающий код должен считать, что словарь для данных интерпретатора недоступен.

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

Введено в версии 3.8.

PyObject* PyThreadState_GetDict()
Значение возврата: Заимствованная ссылка.

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

int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)

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

Изменено в версии 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 расширения вызывается снова. Как и при многофазной инициализации, это означает, что только статические и глобальные переменные на уровне C общие для этих модулей.

void Py_EndInterpreter(PyThreadState *tstate)

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

Проблемы и замечания

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

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

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

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

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

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

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

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

  • на границе байткода;
  • с захватом основной потоком глобальной блокировки интерпретатора (func поэтому может использовать весь C API).

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.

END_OF_DOCUMENT_MARKER

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

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

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

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

Примечание

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

API локального хранения данных для потоков (TSS)

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

Введено в версии 3.7.

См. также

«Новый API C для локального хранения данных для потоков в 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)

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

Примечание

Освобождённый ключ становится висячей ссылкой. Вы должны сбросить ключ до NULL.

Методы

Параметр ключ этих функций не должен быть 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).

Примечание

Эта версия 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()

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/c-api/init.html

Spec-Zone.ru

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