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

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

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

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

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

Примечание

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

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

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

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

int Py_BytesWarningFlag

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

Задается опцией -b.

int Py_DebugFlag

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

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

int Py_DontWriteBytecodeFlag

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

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

int Py_FrozenFlag

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

Закрытый флаг, использоваться программами _freeze_importlib и frozenmain.

int Py_HashRandomizationFlag

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

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

int Py_IgnoreEnvironmentFlag

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

Задается параметрами -E и -I.

int Py_InspectFlag

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

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

int Py_InteractiveFlag

Задается опцией -i.

int Py_IsolatedFlag

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

Задается опцией -I.

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

int Py_LegacyWindowsFSEncodingFlag

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

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

Дополнительные сведения см. в разделе PEP 529.

Availability: Windows.

int Py_LegacyWindowsStdioFlag

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

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

Дополнительные сведения см. в разделе PEP 528.

Availability: 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 внедрения приложения это должно быть вызвано перед использованием любых других функций API Python/C; несколько исключений см. в Перед инициализацией Python.

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

Примечание

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

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 интерпретатора. Она no-op при повторном вызове (без повторного вызова Py_Initialize()). Обычно возвращает значение 0. Если во время завершения (очистка буферизованных данных) возникли ошибки, возвращается -1.

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

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

Raises an auditing event cpython._PySys_ClearAuditHooks with no arguments.

Добавлено в версии 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 всегда использует обработчик ошибки «замены обратного слеша», независимо от этой (или любой другой) настройки.

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

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

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

void Py_SetProgramName(const wchar_t *name)

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

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

wchar* Py_GetProgramName()

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

wchar_t* Py_GetPrefix()

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

wchar_t* Py_GetExecPrefix()

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

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

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

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

w_char* Py_GetPythonHome()

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

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

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

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

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

Примечание

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

Не-Python созданные потоки

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

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

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

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

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

/* Освободите поток. За пределами этого пункта API Python не допускается. */
PyGILState_Release(gstate);

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

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

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

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

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

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

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

PyInterpreterState

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

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

PyThreadState

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

void PyEval_InitThreads()

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

Это «no-op» при повторном вызове.

Изменено в версии 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 GLIEState. Обратите внимание, что главный поток всегда содержит состояние потока, даже если на главном потоке не было сделано вызова авто-поток-состояни. В основном это функция помощника/диагностики.

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()

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

Raises an auditing event cpython.PyInterpreterState_New with no arguments.

void PyInterpreterState_Clear(PyInterpreterState *interp)

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

Raises an auditing event cpython.PyInterpreterState_Clear with no arguments.

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()
Return value: Borrowed reference.

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

int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)

Асинхронное создание исключения в потоке. Аргумент id - 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_SaveThread() является функцией более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).

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 переменной. Он имеет новые стандартные объекты I/O потокового файла 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 принимают взаимно однозначное соответствие между состояниями 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 должна возвращать 0 при успех или -1 при сбое с набором исключений. func не прерывается для рекурсивного выполнения другого асинхронного уведомления, но может быть прервано для переключения потоков, если глобальная блокировка интерпретатора разблокирована.

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

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

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

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

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

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

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

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

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

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

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

int PyTrace_EXCEPTION

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

int PyTrace_LINE

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

int PyTrace_RETURN

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

int PyTrace_C_CALL

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

int PyTrace_C_EXCEPTION

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

int PyTrace_C_RETURN

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

int PyTrace_OPCODE

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

void PyEval_SetProfile(Py_tracefunc func, PyObject *obj)

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

void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)

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

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

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

PyInterpreterState* PyInterpreterState_Head()

Возвращает объект состояния интерпретатора в голове списка всех таких объектов.

PyInterpreterState* PyInterpreterState_Main()

Возвращает основной объект состояния интерпретатора.

PyInterpreterState* PyInterpreterState_Next(PyInterpreterState *interp)

Возвращает следующий объект состояния интерпретатора после interp из списка всех таких объектов.

PyThreadState * PyInterpreterState_ThreadHead(PyInterpreterState *interp)

Возвращает указатель на первый объект PyThreadState в списке потоков, связанных с интерпретатором interp.

PyThreadState* PyThreadState_Next(PyThreadState *tstate)

Возвращает следующий объект состояния потока после tstate из списка всех таких объектов, принадлежащих одному объекту PyInterpreterState.

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

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

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

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

Примечание

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

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

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

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

См.также

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

Py_tss_t

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

Если Py_LIMITED_API не определен, допускается статическое распределение этого типа по Py_tss_NEEDS_INIT.

Py_tss_NEEDS_INIT

Макрос расширяется до инициализатора для Py_tss_t переменных. Обратите внимание, что этот макрос не будет определен с помощью Py_LIMITED_API.

Динамическое распределение

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

Py_tss_t* PyThread_tss_alloc()

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

void PyThread_tss_free(Py_tss_t *key)

Освободить данный key, аллоцированный PyThread_tss_alloc(), после первого вызова PyThread_tss_delete() чтобы убедиться, что все связанные с потоком локальные не назначены. Это операция no-op, если аргумент 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(). Функция может быть вызвана повторно на одном ключе - вызов ее на уже уничтоженном ключе является no-op.

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()