Инициализация, завершение и потоки
См. также Настройка инициализации 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 и 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без открывающей фигурной скобки и объявления переменной.
Низкоуровневый 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_LINEPyTrace_OPCODEиPyTrace_EXCEPTION.
-
void PyEval_SetTrace(Py_tracefunc func, PyObject *obj) -
Установить функцию отслеживания на func. Это аналогично
PyEval_SetProfile(), за исключением того, что функция отслеживания получает события номера строки и события на оператор, но не получает никаких событий, связанных с вызовами объектов функций C. Любая функция отслеживания, зарегистрированная с помощьюPyEval_SetTrace(), не получитPyTrace_C_CALL,PyTrace_C_EXCEPTIONилиPyTrace_C_RETURNв качестве значения для параметра what.
Расширенная поддержка отладчика
Эти функции предназначены только для использования расширенными инструментами отладки.
-
PyInterpreterState* PyInterpreterState_Head() -
Возвращает объект состояния интерпретатора в начале списка всех таких объектов.
-
PyInterpreterState* PyInterpreterState_Main() -
Возвращает основной объект состояния интерпретатора.
-
PyInterpreterState* PyInterpreterState_Next(PyInterpreterState *interp) -
Возвращает следующий объект состояния интерпретатора после interp из списка всех таких объектов.
-
PyThreadState * PyInterpreterState_ThreadHead(PyInterpreterState *interp) -
Возвращает указатель на первый объект
PyThreadStateв списке потоков, связанных с интерпретатором interp.
-
PyThreadState* PyThreadState_Next(PyThreadState *tstate) -
Возвращает следующий объект состояния потока после tstate из списка всех таких объектов, принадлежащих одному объекту
PyInterpreterState.
Поддержка локального хранения для потоков
Интерпретатор Python предоставляет поддержку на низком уровне для локального хранения данных для потоков (TLS), которая оборачивает базовую реализацию родного TLS для поддержки API локального хранения данных для потоков на уровне Python (threading.local). API CPython на уровне C аналогичны API, предлагаемым pthreads и Windows: используется ключ потока и функции для связывания значения void* с каждым потоком.
При вызове этих функций не нужно удерживать GIL; они обеспечивают свою собственную блокировку.
Обратите внимание, что Python.h не включает объявление 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