Инициализация, завершение и потоки
См. также Настройка инициализации 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, которые могут быть установлены.
-
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.
Инициализация и завершение работы интерпретатора
-
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 и macOS,';'в Windows. Возвращаемая строка указывает на статическое хранилище; вызывающий код не должен изменять ее значение. Списокsys.pathинициализируется этим значением при запуске интерпретатора; он может быть (и обычно является) изменён позднее для изменения пути поиска при загрузке модулей.
-
void Py_SetPath(const wchar_t *) -
Устанавливает путь поиска модулей по умолчанию. Если эта функция вызывается до
Py_Initialize(), тоPy_GetPath()не будет пытаться вычислить путь поиска по умолчанию, а вместо этого использует предоставленный. Это полезно, если Python встроен приложением, которое полностью знает местоположение всех модулей. Компоненты пути должны быть разделены платформенно-зависимым разделителем, который равен':'в Unix и macOS,';'в 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'. В macOS —'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() -
Устаревшая функция, которая ничего не делает.
В Python 3.6 и более ранних версиях эта функция создавала блокировку интерпретатора (GIL), если она не существовала.
Изменено в версии 3.9: Функция теперь ничего не делает.
Изменено в версии 3.7: Эта функция теперь вызывается функцией
Py_Initialize(), поэтому вам больше не нужно вызывать её самостоятельно.Изменено в версии 3.2: Эта функция больше не может быть вызвана до
Py_Initialize().Устарело начиная с версии 3.9, будет удалено в версии 3.11.
-
int PyEval_ThreadsInitialized() -
Возвращает ненулевое значение, если была вызвана
PyEval_InitThreads(). Эту функцию можно вызывать без блокировки интерпретатора (GIL), и поэтому ее можно использовать для избежания вызовов API блокировки при выполнении однопоточного кода.Изменено в версии 3.7: Интерпретатор теперь инициализируется функцией
Py_Initialize().Устарело начиная с версии 3.9, будет удалено в версии 3.11.
-
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() -
Гарантирует, что текущий поток готов к вызову C API Python независимо от текущего состояния 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 не использовалось в текущем потоке. Обратите внимание, что основной поток всегда имеет такое состояние потока, даже если для него не вызывались функции из API GILState. В основном это вспомогательная/диагностическая функция.
-
int PyGILState_Check() -
Возвращает
1если текущий поток держит GIL и0в противном случае. Эту функцию можно вызывать из любого потока в любое время. Она вернёт1только если у потока инициализировано состояние потока Python и он держит GIL. В основном это вспомогательная/диагностическая функция. Она может быть полезна, например, в контекстах обратного вызова или функциях выделения памяти, когда знание, что 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: 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) -
Сбрасывает всю информацию в объекте состояния потока. Блокировка глобального интерпретатора должна быть взята.
Изменено в версии 3.9: Эта функция теперь вызывает обратный вызов
PyThreadState.on_delete. Раньше это происходило вPyThreadState_Delete().
-
void PyThreadState_Delete(PyThreadState *tstate) -
Уничтожает объект состояния потока. Блокировка глобального интерпретатора не требуется. Состояние потока должно быть сброшено с помощью предыдущего вызова
PyThreadState_Clear().
-
void PyThreadState_DeleteCurrent(void) -
Уничтожает текущее состояние потока и освобождает блокировку глобального интерпретатора. Как и
PyThreadState_Delete(), блокировка глобального интерпретатора не требуется. Состояние потока должно быть сброшено с помощью предыдущего вызоваPyThreadState_Clear().
-
PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) -
Возвращает текущую рамку состояния потока Python tstate.
Возвращает сильную ссылку. Возвращает
NULL, если в данный момент ни одна рамка не выполняется.См. также
PyEval_GetFrame().tstate не должен быть
NULL.Добавлена в версии 3.9.
-
uint64_t PyThreadState_GetID(PyThreadState *tstate) -
Возвращает уникальный идентификатор состояния потока объекта состояния потока Python tstate.
tstate не должен быть
NULL.Добавлена в версии 3.9.
-
PyInterpreterState* PyThreadState_GetInterpreter(PyThreadState *tstate) -
Возвращает интерпретатор объекта состояния потока Python tstate.
tstate не должен быть
NULL.Добавлена в версии 3.9.
-
PyInterpreterState* PyInterpreterState_Get(void) -
Возвращает текущий интерпретатор.
Выдает ошибку, если нет текущего состояния потока Python или текущего интерпретатора. Не может вернуть NULL.
Вызывающая сторона должна держать GIL.
Добавлена в версии 3.9.
-
int64_t PyInterpreterState_GetID(PyInterpreterState *interp) -
Возвращает уникальный ID интерпретатора. Если произошла ошибка, возвращается
-1, и устанавливается ошибка.Вызывающая сторона должна держать GIL.
Добавлена в версии 3.7.
-
PyObject* PyInterpreterState_GetDict(PyInterpreterState *interp) -
Возвращает словарь, в котором можно хранить данные, специфичные для интерпретатора. Если эта функция возвращает
NULL, исключение не было возбуждено, и вызывающая сторона должна предположить, что словарь, специфичный для интерпретатора, недоступен.Это не замена
PyModule_GetState(), которую расширения должны использовать для хранения информации о состоянии, специфичной для интерпретатора.Добавлена в версии 3.8.
-
PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *frame, int throwflag) -
Тип функции оценки кадра.
Параметр throwflag используется методом
throw()генераторов: если он отличен от нуля, обработайте текущее исключение.Изменено в версии 3.9: Функция теперь принимает параметр tstate.
-
_PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) -
Возвращает функцию оценки кадра.
См. PEP 523 «Добавление API оценки кадра в CPython».
Добавлена в версии 3.9.
-
void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame) -
Устанавливает функцию оценки кадра.
См. PEP 523 «Добавление API оценки кадра в CPython».
Добавлена в версии 3.9.
-
PyObject* PyThreadState_GetDict() -
Возвращаемое значение: Заимствованная ссылка.
Возвращает словарь, в котором расширения могут хранить информацию о состоянии, специфичную для потока. Каждое расширение должно использовать уникальный ключ для хранения состояния в словаре. Вызов этой функции допустим, даже когда нет текущего состояния потока. Если эта функция возвращает
NULL, исключение не было возбуждено, и вызывающая сторона должна предположить, что текущее состояние потока недоступно.
-
int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) -
Асинхронно возбуждает исключение в потоке. Аргумент id — идентификатор целевого потока; exc — объект исключения, который нужно возбудить. Эта функция не заимствует никакие ссылки на exc. Для предотвращения неочевидного использования необходимо написать собственное расширение C для вызова этой функции. Должен вызываться с захваченным GIL. Возвращает количество изменённых состояний потоков; обычно это один, но будет ноль, если идентификатор потока не найден. Если 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(), они могут (случайно или злонамеренно) влиять на открытые файлы друг друга. Из-за способа, которым расширения разделяются между (под-)интерпретаторами, некоторые расширения могут работать неправильно; это особенно вероятно при использовании однофазной инициализации или (статических) глобальных переменных. Можно вставлять объекты, созданные в одном под-интерпретаторе, в пространство имен другого (под-)интерпретатора; этого следует избегать, если это возможно.
Особое внимание следует уделить тому, чтобы избегать совместного использования пользовательских функций, методов, экземпляров или классов между под-интерпретаторами, поскольку операции импорта, выполняемые такими объектами, могут повлиять на словарь загруженных модулей неправильного (под-)интерпретатора. Точно так же важно избегать совместного использования объектов, до которых можно добраться из вышеперечисленных.
Также обратите внимание, что сочетание этой функциональности с API PyGILState_*() API является тонким, так как эти API предполагают взаимно однозначное соответствие между состояниями потоков Python и потоками на уровне ОС, предположение, нарушаемое наличием под-интерпретаторов. Сильно рекомендуется не переключаться между под-интерпретаторами между парой вызовов PyGILState_Ensure() и PyGILState_Release(). Кроме того, расширения (например, ctypes), использующие эти API для вызова кода Python из потоков, созданных вне Python, вероятно, сломаются при использовании под-интерпретаторов.
Асинхронные уведомления
Предоставлен механизм для асинхронных уведомлений основной интерпретирующей нити. Эти уведомления представляют собой указатель на функцию и аргумент типа указатель на void.
-
int Py_AddPendingCall(int (*func)(void *), void *arg) -
Планирует вызов функции из основной интерпретирующей нити. При успехе возвращается
0и func помещается в очередь для вызова в основной нити. При ошибке возвращается-1без установки исключения.После успешного помещения в очередь, func будет в конечном итоге вызвана из основной интерпретирующей нити с аргументом arg. Она будет вызвана асинхронно относительно обычно выполняемого Python-кода, но при соблюдении этих условий:
- на границе байт-кода;
- с удержанием основной нитью глобальной блокировки интерпретатора (func может поэтому использовать весь C API).
func должна возвращать
0при успехе или-1при ошибке с установленным исключением. func не будет прервана для выполнения другого асинхронного уведомления рекурсивно, но она все же может быть прервана для переключения нитей, если глобальная блокировка интерпретатора освобождена.Эта функция не нуждается в текущем состоянии нити для выполнения и не требует глобальной блокировки интерпретатора.
Для вызова этой функции в подинтерпретаторе вызывающий должен удерживать GIL. В противном случае функция func может быть запланирована на вызов из неправильного интерпретатора.
Предупреждение
Это функция низкого уровня, полезная только в очень особых случаях. Нет гарантии, что func будет вызвана как можно быстрее. Если основная нить занята выполнением системного вызова, func не будет вызвана до возврата из системного вызова. Эта функция, как правило, не подходит для вызова Python-кода из произвольных C-нитей. Используйте вместо этого API PyGILState.
Изменено в версии 3.9: Если эта функция вызывается в подинтерпретаторе, функция func теперь планируется для вызова из подинтерпретатора, а не из основного интерпретатора. Каждый подинтерпретатор теперь имеет свой собственный список запланированных вызовов.
Добавлена в версии 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при сообщении о новом вызове функции или метода или новом входе в генератор. Обратите внимание, что создание итератора для генераторной функции не сообщается, так как нет передачи управления байт-коду в соответствующем фрейме.
-
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_LINEPyTrace_OPCODEиPyTrace_EXCEPTION.Вызывающий должен удерживать GIL.
-
void PyEval_SetTrace(Py_tracefunc func, PyObject *obj) -
Устанавливает функцию отслеживания на func. Это аналогично
PyEval_SetProfile(), за исключением того, что функция отслеживания получает события номера строки и события по каждому оператору, но не получает события, связанные с вызовами C-функций. Любая функция отслеживания, зарегистрированная с помощьюPyEval_SetTrace(), не получитPyTrace_C_CALL,PyTrace_C_EXCEPTIONилиPyTrace_C_RETURNв качестве значения параметра what.Вызывающий должен удерживать GIL.
Расширенная поддержка отладчика
Эти функции предназначены только для использования расширенными инструментами отладки.
-
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 не включает объявление API TLS, вам необходимо включить pythread.h для использования локального хранения данных в потоке.
Примечание
Ни одна из этих функций API не обрабатывает управление памятью от имени значений void*. Вам необходимо выделять и освобождать их самостоятельно. Если значения void* оказываются PyObject*, эти функции также не выполняют операции с счётчиком ссылок.
API локального хранения данных в потоке (TSS)
API TSS введен для замены использования существующего API TLS в интерпретаторе 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) -
Освобождает заданный ключ, выделенный с помощью
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).
Примечание
Эта версия 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.9/c-api/init.html