初始化、最终化和线程¶
有关如何在初始化之前配置解释器的详细信息,请参阅Python 初始化配置。
Python 初始化之前¶
在嵌入 Python 的应用程序中,必须在调用任何其他 Python/C API 函数之前调用Py_Initialize()
函数;除了少数函数和全局配置变量。
以下函数可以在 Python 初始化之前安全调用
初始化解释器的函数
配置函数
信息函数
实用程序
在Python 初始化配置中介绍的状态报告和实用程序函数
内存分配器
同步
注意
尽管它们与上面列出的某些函数明显相似,但在解释器初始化之前,不应调用以下函数:Py_EncodeLocale()
, Py_GetPath()
, Py_GetPrefix()
, Py_GetExecPrefix()
, Py_GetProgramFullPath()
, Py_GetPythonHome()
, Py_GetProgramName()
, PyEval_InitThreads()
, 和 Py_RunMain()
。
全局配置变量¶
Python 具有用于全局配置的变量,以控制不同的功能和选项。默认情况下,这些标志由命令行选项控制。
当一个标志被一个选项设置时,该标志的值是该选项被设置的次数。 例如,-b
将Py_BytesWarningFlag
设置为 1,-bb
将Py_BytesWarningFlag
设置为 2。
-
int Py_BytesWarningFlag¶
保留此 API 以实现向后兼容性:应使用设置
PyConfig.bytes_warning
,请参阅Python 初始化配置。当比较
bytes
或bytearray
与str
或bytes
与int
时发出警告。如果大于或等于2
,则发出错误。由
-b
选项设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_DebugFlag¶
保留此 API 以实现向后兼容性:应使用设置
PyConfig.parser_debug
,请参阅Python 初始化配置。打开解析器调试输出(仅供专家使用,取决于编译选项)。
由
-d
选项和PYTHONDEBUG
环境变量设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_DontWriteBytecodeFlag¶
保留此 API 以实现向后兼容性:应使用设置
PyConfig.write_bytecode
,请参阅Python 初始化配置。如果设置为非零值,Python 将不会尝试在导入源模块时写入
.pyc
文件。由
-B
选项和PYTHONDONTWRITEBYTECODE
环境变量设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_FrozenFlag¶
保留此 API 以实现向后兼容性:应使用设置
PyConfig.pathconfig_warnings
,请参阅Python 初始化配置。在
Py_GetPath()
中计算模块搜索路径时,禁止显示错误消息。由
_freeze_module
和frozenmain
程序使用的私有标志。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_HashRandomizationFlag¶
保留此 API 以实现向后兼容性:应使用设置
PyConfig.hash_seed
和PyConfig.use_hash_seed
,请参阅Python 初始化配置。如果
PYTHONHASHSEED
环境变量设置为非空字符串,则设置为1
。如果该标志非零,则读取
PYTHONHASHSEED
环境变量以初始化秘密哈希种子。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_IgnoreEnvironmentFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.use_environment
,请参阅 Python 初始化配置。忽略所有
PYTHON*
环境变量,例如PYTHONPATH
和PYTHONHOME
,这些变量可能会被设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_InspectFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.inspect
,请参阅 Python 初始化配置。当脚本作为第一个参数传递,或者使用了
-c
选项时,即使sys.stdin
看起来不是终端,也会在执行脚本或命令后进入交互模式。由
-i
选项和PYTHONINSPECT
环境变量设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_InteractiveFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.interactive
,请参阅 Python 初始化配置。由
-i
选项设置。自 3.12 版本起已弃用。
-
int Py_IsolatedFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.isolated
,请参阅 Python 初始化配置。在隔离模式下运行 Python。在隔离模式下,
sys.path
既不包含脚本的目录,也不包含用户的 site-packages 目录。由
-I
选项设置。在 3.4 版本中添加。
自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_LegacyWindowsFSEncodingFlag¶
此 API 保留是为了向后兼容:应使用设置
PyPreConfig.legacy_windows_fs_encoding
,请参阅 Python 初始化配置。如果该标志为非零值,则使用
mbcs
编码和replace
错误处理程序,而不是 UTF-8 编码和surrogatepass
错误处理程序,用于 文件系统编码和错误处理程序。如果
PYTHONLEGACYWINDOWSFSENCODING
环境变量设置为非空字符串,则设置为1
。有关更多详细信息,请参阅 PEP 529。
可用性:Windows。
自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_LegacyWindowsStdioFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.legacy_windows_stdio
,请参阅 Python 初始化配置。如果该标志为非零值,则对
sys
标准流使用io.FileIO
而不是io._WindowsConsoleIO
。如果
PYTHONLEGACYWINDOWSSTDIO
环境变量设置为非空字符串,则设置为1
。有关更多详细信息,请参阅 PEP 528。
可用性:Windows。
自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_NoSiteFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.site_import
,请参阅 Python 初始化配置。禁用模块
site
的导入以及由此引起的对sys.path
的站点相关操作。如果稍后显式导入site
,也禁用这些操作(如果要触发这些操作,请调用site.main()
)。由
-S
选项设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_NoUserSiteDirectory¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.user_site_directory
,请参阅 Python 初始化配置。不要将
用户 site-packages 目录
添加到sys.path
。由
-s
和-I
选项以及PYTHONNOUSERSITE
环境变量设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_OptimizeFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.optimization_level
,请参阅 Python 初始化配置。由
-O
选项和PYTHONOPTIMIZE
环境变量设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_QuietFlag¶
此 API 保留是为了向后兼容:应使用设置
PyConfig.quiet
,请参阅 Python 初始化配置。即使在交互模式下也不显示版权和版本信息。
由
-q
选项设置。在 3.2 版本中添加。
自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_UnbufferedStdioFlag¶
此 API 保留用于向后兼容:应使用
PyConfig.buffered_stdio
来代替,请参阅 Python 初始化配置。强制 stdout 和 stderr 流不使用缓冲。
由
-u
选项和PYTHONUNBUFFERED
环境变量设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
-
int Py_VerboseFlag¶
此 API 保留用于向后兼容:应使用
PyConfig.verbose
来代替,请参阅 Python 初始化配置。每次初始化模块时都打印一条消息,显示模块的加载位置(文件名或内置模块)。如果大于或等于
2
,则为搜索模块时检查的每个文件打印一条消息。还提供有关退出时模块清理的信息。由
-v
选项和PYTHONVERBOSE
环境变量设置。自 3.12 版本起已弃用,将在 3.14 版本中删除。
初始化和终止解释器¶
-
void Py_Initialize()¶
- 属于 稳定 ABI 的一部分。
初始化 Python 解释器。在嵌入 Python 的应用程序中,应在调用任何其他 Python/C API 函数之前调用此函数;有关少数例外情况,请参阅 Python 初始化之前。
这将初始化已加载模块的表(
sys.modules
),并创建基本模块builtins
、__main__
和sys
。它还会初始化模块搜索路径(sys.path
)。它不会设置sys.argv
;请使用 Python 初始化配置 API。如果第二次调用此函数(在未先调用Py_FinalizeEx()
的情况下),则此函数不执行任何操作。没有返回值;如果初始化失败,则会发生致命错误。使用
Py_InitializeFromConfig()
自定义 Python 初始化配置。注意
在 Windows 上,将控制台模式从
O_TEXT
更改为O_BINARY
,这也将影响使用 C 运行时控制台的非 Python 用途。
-
void Py_InitializeEx(int initsigs)¶
- 属于 稳定 ABI 的一部分。
如果 initsigs 为
1
,则此函数的工作方式类似于Py_Initialize()
。如果 initsigs 为0
,则它会跳过信号处理程序的初始化注册,当 CPython 作为大型应用程序的一部分嵌入时,这可能很有用。
-
PyStatus Py_InitializeFromConfig(const PyConfig *config)¶
从 config 配置初始化 Python,如 使用 PyConfig 初始化 中所述。
有关预初始化解释器、填充运行时配置结构和查询返回的状态结构的详细信息,请参阅 Python 初始化配置 部分。
-
int Py_IsInitialized()¶
- 属于 稳定 ABI 的一部分。
当 Python 解释器已初始化时返回 true(非零),如果未初始化则返回 false(零)。在调用
Py_FinalizeEx()
之后,此函数将返回 false,直到再次调用Py_Initialize()
。
-
int Py_IsFinalizing()¶
- 自 3.13 版本起,属于 稳定 ABI 的一部分。
如果主 Python 解释器正在 关闭,则返回 true(非零)。否则返回 false(零)。
3.13 版本中新增。
-
int Py_FinalizeEx()¶
- 自 3.6 版本起,属于 稳定 ABI 的一部分。
撤消
Py_Initialize()
所做的所有初始化以及后续对 Python/C API 函数的使用,并销毁自上次调用Py_Initialize()
以来创建但尚未销毁的所有子解释器(请参阅下面的Py_NewInterpreter()
)。理想情况下,这将释放 Python 解释器分配的所有内存。如果第二次调用此函数(在未先调用Py_Initialize()
的情况下),则此函数不执行任何操作。由于这是
Py_Initialize()
的反向操作,因此应在同一线程中以相同活动的解释器调用它。这意味着主线程和主解释器。当Py_RunMain()
正在运行时,绝不应调用此函数。通常,返回值是
0
。如果在终止期间(刷新缓冲数据)出现错误,则返回-1
。提供此函数的原因有很多。嵌入式应用程序可能希望在无需重新启动应用程序本身的情况下重新启动 Python。从动态可加载库(或 DLL)加载 Python 解释器的应用程序可能希望在卸载 DLL 之前释放 Python 分配的所有内存。在应用程序中查找内存泄漏期间,开发人员可能希望在从应用程序退出之前释放 Python 分配的所有内存。
Bug 和注意事项: 模块和模块中对象的销毁以随机顺序完成;当析构函数(
__del__()
方法)依赖于其他对象(甚至函数)或模块时,这可能会导致其失败。Python 加载的动态加载的扩展模块不会卸载。Python 解释器分配的少量内存可能不会释放(如果您发现内存泄漏,请报告)。对象之间的循环引用占用的内存不会释放。扩展模块分配的某些内存可能不会释放。如果多次调用它们的初始化例程,则某些扩展可能无法正常工作;如果应用程序多次调用Py_Initialize()
和Py_FinalizeEx()
,则可能会发生这种情况。引发一个 审计事件
cpython._PySys_ClearAuditHooks
,不带任何参数。3.6 版本中新增。
-
void Py_Finalize()¶
- 属于 稳定 ABI 的一部分。
这是
Py_FinalizeEx()
的向后兼容版本,它忽略返回值。
-
int Py_BytesMain(int argc, char **argv)¶
- 自 3.8 版本起,属于 稳定 ABI 的一部分。
类似于
Py_Main()
,但 argv 是字节字符串数组,允许调用应用程序将文本解码步骤委派给 CPython 运行时。3.8 版本中新增。
-
int Py_Main(int argc, wchar_t **argv)¶
- 属于 稳定 ABI 的一部分。
标准解释器的主程序,封装了完整的初始化/最终化周期,以及从环境和命令行读取配置设置的附加行为,然后根据命令行执行
__main__
。此功能适用于希望支持完整的 CPython 命令行界面,而不仅仅是将 Python 运行时嵌入到更大的应用程序中的程序。
argc 和 argv 参数类似于传递给 C 程序的
main()
函数的参数,只是 argv 条目首先使用Py_DecodeLocale()
转换为wchar_t
。 同样重要的是要注意,参数列表条目可能会被修改以指向与传入的字符串不同的字符串(但是,参数列表指向的字符串的内容不会被修改)。如果解释器正常退出(即没有异常),则返回值将为
0
;如果解释器因异常退出,则返回值将为1
;如果参数列表不表示有效的 Python 命令行,则返回值将为2
。请注意,如果引发了原本未处理的
SystemExit
,则只要未设置Py_InspectFlag
,此函数将不会返回1
,而是退出进程。如果设置了Py_InspectFlag
,执行将进入交互式 Python 提示符,此时,第二个未处理的SystemExit
仍将退出进程,而任何其他退出方式都将如上所述设置返回值。就运行时配置部分中记录的 CPython 运行时配置 API 而言(且不考虑错误处理),
Py_Main
大致等效于PyConfig config; PyConfig_InitPythonConfig(&config); PyConfig_SetArgv(&config, argc, argv); Py_InitializeFromConfig(&config); PyConfig_Clear(&config); Py_RunMain();
在正常使用中,嵌入应用程序将调用此函数,而不是 直接调用
Py_Initialize()
、Py_InitializeEx()
或Py_InitializeFromConfig()
,并且所有设置都将按本文档的其他地方所述应用。如果此函数是在先前的运行时初始化 API 调用之后调用的,则哪些环境和命令行配置设置将被更新取决于版本(因为它取决于哪些设置在运行时首次初始化时已正确支持在设置一次后进行修改)。
-
int Py_RunMain(void)¶
在完全配置的 CPython 运行时中执行主模块。
执行在命令行或配置中指定的命令(
PyConfig.run_command
)、脚本(PyConfig.run_filename
)或模块(PyConfig.run_module
)。如果未设置这些值,则使用__main__
模块的全局命名空间运行交互式 Python 提示符 (REPL)。如果未设置
PyConfig.inspect
(默认值),则如果解释器正常退出(即没有引发异常),则返回值将为0
;如果解释器因异常退出,则返回值将为1
。如果引发了原本未处理的SystemExit
,则该函数将立即退出进程,而不是返回1
。如果设置了
PyConfig.inspect
(例如,当使用-i
选项时),则在解释器退出时,执行不会返回,而是在使用__main__
模块的全局命名空间的交互式 Python 提示符 (REPL) 中恢复。如果解释器因异常而退出,它会立即在 REPL 会话中引发。然后,函数返回值由 REPL 会话 终止的方式确定:如果会话在没有引发未处理异常的情况下终止,则返回0
;对于未处理的SystemExit
,则立即退出;对于任何其他未处理的异常,则返回1
。此函数始终会最终化 Python 解释器,无论它是返回值还是因未处理的
SystemExit
异常而立即退出进程。有关使用
Py_RunMain()
始终以隔离模式运行的自定义 Python 的示例,请参阅 Python 配置。
-
int PyUnstable_AtExit(PyInterpreterState *interp, void (*func)(void*), void *data)¶
- 这是不稳定 API。 它可能会在次要版本中更改,恕不另行通知。
为目标解释器 interp 注册一个
atexit
回调。 这类似于Py_AtExit()
,但为回调采用显式的解释器和数据指针。必须为 interp 持有 GIL。
3.13 版本中新增。
进程范围的参数¶
-
void Py_SetProgramName(const wchar_t *name)¶
- 属于 稳定 ABI 的一部分。
保留此 API 以实现向后兼容性:应改用设置
PyConfig.program_name
,请参阅 Python 初始化配置。如果调用此函数,则应在第一次调用
Py_Initialize()
之前调用此函数。 它告诉解释器程序的main()
函数的argv[0]
参数的值(转换为宽字符)。Py_GetPath()
和下面的一些其他函数使用它来查找相对于解释器可执行文件的 Python 运行时库。 默认值为'python'
。 参数应指向静态存储中的以零结尾的宽字符串,该字符串的内容在程序执行期间不会更改。 Python 解释器中的任何代码都不会更改此存储的内容。使用
Py_DecodeLocale()
解码字节字符串以获取 wchar_* 字符串。自 3.11 版本起已弃用。
-
wchar_t *Py_GetProgramName()¶
- 属于 稳定 ABI 的一部分。
返回使用
PyConfig.program_name
设置的程序名称,或者默认名称。返回的字符串指向静态存储区;调用者不应修改其值。此函数不应在
Py_Initialize()
之前调用,否则将返回NULL
。在 3.10 版本中更改: 如果在此函数在
Py_Initialize()
之前调用,则现在返回NULL
。自 3.13 版本起已弃用,将在 3.15 版本中删除: 请改用
sys.executable
。
-
wchar_t *Py_GetPrefix()¶
- 属于 稳定 ABI 的一部分。
返回已安装的平台无关文件的前缀。这是通过一些复杂的规则从使用
PyConfig.program_name
设置的程序名称和一些环境变量派生而来的;例如,如果程序名称是'/usr/local/bin/python'
,则前缀是'/usr/local'
。返回的字符串指向静态存储区;调用者不应修改其值。这对应于顶层Makefile
中的 prefix 变量以及构建时 configure 脚本的--prefix
参数。该值在 Python 代码中可用作sys.base_prefix
。它仅在 Unix 上有用。另请参阅下一个函数。此函数不应在
Py_Initialize()
之前调用,否则将返回NULL
。在 3.10 版本中更改: 如果在此函数在
Py_Initialize()
之前调用,则现在返回NULL
。自 3.13 版本起已弃用,将在 3.15 版本中删除: 请改用
sys.base_prefix
,或者如果需要处理虚拟环境,请使用sys.prefix
。
-
wchar_t *Py_GetExecPrefix()¶
- 属于 稳定 ABI 的一部分。
返回已安装的平台相关文件的执行前缀。这是通过一些复杂的规则从使用
PyConfig.program_name
设置的程序名称和一些环境变量派生而来的;例如,如果程序名称是'/usr/local/bin/python'
,则执行前缀是'/usr/local'
。返回的字符串指向静态存储区;调用者不应修改其值。这对应于顶层Makefile
中的 exec_prefix 变量以及构建时 configure 脚本的--exec-prefix
参数。该值在 Python 代码中可用作sys.base_exec_prefix
。它仅在 Unix 上有用。背景:当平台相关文件(例如可执行文件和共享库)安装在不同的目录树中时,执行前缀与前缀不同。在典型的安装中,平台相关文件可以安装在
/usr/local/plat
子树中,而平台无关文件可以安装在/usr/local
中。一般来说,平台是硬件和软件系列的组合,例如,运行 Solaris 2.x 操作系统的 Sparc 机器被认为是同一平台,但运行 Solaris 2.x 的 Intel 机器是另一个平台,而运行 Linux 的 Intel 机器又是另一个平台。同一操作系统不同主要版本通常也构成不同的平台。非 Unix 操作系统则是另一回事;这些系统上的安装策略差异很大,以至于前缀和执行前缀没有意义,并设置为空字符串。请注意,编译后的 Python 字节码文件是平台无关的(但并非独立于编译它们的 Python 版本!)。
系统管理员将知道如何配置 mount 或 automount 程序以在平台之间共享
/usr/local
,同时使/usr/local/plat
成为每个平台不同的文件系统。此函数不应在
Py_Initialize()
之前调用,否则将返回NULL
。在 3.10 版本中更改: 如果在此函数在
Py_Initialize()
之前调用,则现在返回NULL
。自 3.13 版本起已弃用,将在 3.15 版本中删除: 请改用
sys.base_exec_prefix
,或者如果需要处理虚拟环境,请使用sys.exec_prefix
。
-
wchar_t *Py_GetProgramFullPath()¶
- 属于 稳定 ABI 的一部分。
返回 Python 可执行文件的完整程序名称;这是从程序名称(由
PyConfig.program_name
设置)派生默认模块搜索路径的副作用计算出来的。返回的字符串指向静态存储区;调用者不应修改其值。该值在 Python 代码中可用作sys.executable
。此函数不应在
Py_Initialize()
之前调用,否则将返回NULL
。在 3.10 版本中更改: 如果在此函数在
Py_Initialize()
之前调用,则现在返回NULL
。自 3.13 版本起已弃用,将在 3.15 版本中删除: 请改用
sys.executable
。
-
wchar_t *Py_GetPath()¶
- 属于 稳定 ABI 的一部分。
返回默认模块搜索路径;这是从程序名称(由
PyConfig.program_name
设置)和一些环境变量计算出来的。返回的字符串由一系列以平台相关分隔符分隔的目录名称组成。分隔符在 Unix 和 macOS 上是':'
,在 Windows 上是';'
。返回的字符串指向静态存储区;调用者不应修改其值。列表sys.path
在解释器启动时使用此值初始化;它可以(并且通常是)在以后修改以更改加载模块的搜索路径。此函数不应在
Py_Initialize()
之前调用,否则将返回NULL
。在 3.10 版本中更改: 如果在此函数在
Py_Initialize()
之前调用,则现在返回NULL
。自 3.13 版本起已弃用,将在 3.15 版本中删除: 请改用
sys.path
。
-
const char *Py_GetVersion()¶
- 属于 稳定 ABI 的一部分。
返回此 Python 解释器的版本。这是一个类似于以下的字符串
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
第一个单词(直到第一个空格字符)是当前的 Python 版本;前几个字符是主要版本和次要版本,用句点分隔。返回的字符串指向静态存储区;调用者不应修改其值。该值在 Python 代码中可用作
sys.version
。另请参阅
Py_Version
常量。
-
const char *Py_GetPlatform()¶
- 属于 稳定 ABI 的一部分。
返回当前平台的平台标识符。在 Unix 上,它由操作系统的“官方”名称组成,转换为小写,后跟主要修订号;例如,对于也称为 SunOS 5.x 的 Solaris 2.x,该值为
'sunos5'
。在 macOS 上,它是'darwin'
。在 Windows 上,它是'win'
。返回的字符串指向静态存储区;调用者不应修改其值。该值在 Python 代码中可用作sys.platform
。
-
const char *Py_GetCopyright()¶
- 属于 稳定 ABI 的一部分。
返回当前 Python 版本的官方版权字符串,例如:
'Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam'
返回的字符串指向静态存储区;调用者不应修改其值。该值在 Python 代码中可作为
sys.copyright
使用。
-
const char *Py_GetCompiler()¶
- 属于 稳定 ABI 的一部分。
返回一个指示用于构建当前 Python 版本的编译器的字符串,用方括号括起来,例如:
"[GCC 2.7.2.2]"
返回的字符串指向静态存储区;调用者不应修改其值。该值在 Python 代码中可作为变量
sys.version
的一部分使用。
-
const char *Py_GetBuildInfo()¶
- 属于 稳定 ABI 的一部分。
返回有关当前 Python 解释器实例的序列号、构建日期和时间的信息,例如:
"#67, Aug 1 1997, 22:34:28"
返回的字符串指向静态存储区;调用者不应修改其值。该值在 Python 代码中可作为变量
sys.version
的一部分使用。
-
void PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)¶
- 属于 稳定 ABI 的一部分。
保留此 API 是为了向后兼容:应使用设置
PyConfig.argv
、PyConfig.parse_argv
和PyConfig.safe_path
,请参阅 Python 初始化配置。基于 argc 和 argv 设置
sys.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_* 字符串。另请参阅
PyConfig.orig_argv
和PyConfig.argv
,它们是 Python 初始化配置 的成员。注意
建议将 Python 解释器嵌入到除执行单个脚本以外的其他用途的应用程序将
0
作为 updatepath 传递,并在需要时自行更新sys.path
。请参阅 CVE 2008-5983。在 3.1.3 之前的版本中,您可以通过在调用
PySys_SetArgv()
后手动弹出第一个sys.path
元素来实现相同的效果,例如使用:PyRun_SimpleString("import sys; sys.path.pop(0)\n");
在 3.1.3 版本中新增。
自 3.11 版本起已弃用。
-
void PySys_SetArgv(int argc, wchar_t **argv)¶
- 属于 稳定 ABI 的一部分。
保留此 API 是为了向后兼容:应使用设置
PyConfig.argv
和PyConfig.parse_argv
,请参阅 Python 初始化配置。此函数的工作方式类似于
PySys_SetArgvEx()
,其中 updatepath 设置为1
,除非使用-I
选项启动了 python 解释器。使用
Py_DecodeLocale()
解码字节字符串以获取 wchar_* 字符串。另请参阅
PyConfig.orig_argv
和PyConfig.argv
,它们是 Python 初始化配置 的成员。在 3.4 版本中更改: updatepath 值取决于
-I
。自 3.11 版本起已弃用。
-
void Py_SetPythonHome(const wchar_t *home)¶
- 属于 稳定 ABI 的一部分。
保留此 API 是为了向后兼容:应使用设置
PyConfig.home
,请参阅 Python 初始化配置。设置默认的“home”目录,即标准 Python 库的位置。有关参数字符串的含义,请参阅
PYTHONHOME
。此参数应指向静态存储区中以零结尾的字符字符串,该字符串的内容在程序执行期间不会更改。Python 解释器中的任何代码都不会更改此存储区的内容。
使用
Py_DecodeLocale()
解码字节字符串以获取 wchar_* 字符串。自 3.11 版本起已弃用。
-
wchar_t *Py_GetPythonHome()¶
- 属于 稳定 ABI 的一部分。
返回默认的“home”,即
PyConfig.home
设置的值,或者如果设置了PYTHONHOME
环境变量,则返回其值。此函数不应在
Py_Initialize()
之前调用,否则将返回NULL
。在 3.10 版本中更改: 如果在此函数在
Py_Initialize()
之前调用,则现在返回NULL
。自 3.13 版本起弃用, 将在 3.15 版本中移除: 请改为获取
PyConfig.home
或PYTHONHOME
环境变量。
线程状态和全局解释器锁¶
Python 解释器不是完全线程安全的。为了支持多线程 Python 程序,存在一个全局锁,称为全局解释器锁或GIL,当前线程必须持有该锁才能安全地访问 Python 对象。如果没有锁,即使是最简单的操作也可能在多线程程序中导致问题:例如,当两个线程同时递增同一对象的引用计数时,引用计数可能最终只递增一次而不是两次。
因此,规则规定,只有获取了 GIL 的线程才能操作 Python 对象或调用 Python/C API 函数。为了模拟并发执行,解释器会定期尝试切换线程(请参阅 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);
以下是这些函数的工作方式:全局解释器锁用于保护指向当前线程状态的指针。当释放锁并保存线程状态时,必须在释放锁之前检索当前线程状态指针(因为另一个线程可能会立即获取锁并将自己的线程状态存储在全局变量中)。相反,当获取锁并恢复线程状态时,必须在存储线程状态指针之前获取锁。
非 Python 创建的线程¶
当使用专用的 Python API(例如 threading
模块)创建线程时,会自动将线程状态与它们关联,因此上面显示的代码是正确的。但是,当从 C 创建线程时(例如,由具有自己线程管理的第三方库创建),它们不持有 GIL,也没有它们的线程状态结构。
如果需要从这些线程调用 Python 代码(通常这将是上述第三方库提供的回调 API 的一部分),则必须首先通过创建线程状态数据结构向解释器注册这些线程,然后获取 GIL,最后存储其线程状态指针,然后才能开始使用 Python/C API。完成后,应重置线程状态指针,释放 GIL,最后释放线程状态数据结构。
PyGILState_Ensure()
和 PyGILState_Release()
函数会自动完成上述所有操作。从 C 线程调用 Python 的典型习惯用法是
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()
),但不支持混合使用多个解释器和 PyGILState_*
API。
关于 fork() 的注意事项¶
关于线程,另一个需要注意的重要事项是它们在面对 C fork()
调用时的行为。在大多数带有 fork()
的系统上,在进程 fork 之后,只有发出 fork 的线程才会存在。这对锁的处理方式以及 CPython 运行时中的所有存储状态都有具体影响。
仅保留“当前”线程这一事实意味着其他线程持有的任何锁都将永远不会被释放。Python 通过在 fork 之前获取其内部使用的锁并在之后释放它们来解决 os.fork()
的问题。此外,它会重置子进程中的任何 锁对象。在扩展或嵌入 Python 时,无法通知 Python 在 fork 之前需要获取或在 fork 之后需要重置的其他(非 Python)锁。需要使用诸如 pthread_atfork()
之类的操作系统工具来完成相同的操作。此外,在扩展或嵌入 Python 时,直接调用 fork()
而不是通过 os.fork()
(并返回或调用 Python)可能会导致死锁,因为 Python 的内部锁之一被 fork 后失效的线程持有。PyOS_AfterFork_Child()
尝试重置必要的锁,但并非总是能够成功。
所有其他线程都消失的事实也意味着必须正确清理 CPython 的运行时状态,而 os.fork()
会执行此操作。这意味着最终确定当前解释器拥有的所有其他 PyThreadState
对象和所有其他 PyInterpreterState
对象。由于此原因以及 “主”解释器 的特殊性,fork()
只能在该解释器的“主”线程中调用,在该线程中最初初始化了 CPython 全局运行时。唯一的例外是如果 exec()
将在之后立即被调用。
高级 API¶
这些是在编写 C 扩展代码或嵌入 Python 解释器时最常用的类型和函数
-
type PyInterpreterState¶
- 是 有限 API 的一部分(作为不透明结构)。
此数据结构表示多个协作线程共享的状态。属于同一解释器的线程共享其模块管理和一些其他内部项。此结构中没有公共成员。
属于不同解释器的线程最初不共享任何内容,除了进程状态(如可用内存、打开的文件描述符等)。全局解释器锁也由所有线程共享,无论它们属于哪个解释器。
-
type PyThreadState¶
- 是 有限 API 的一部分(作为不透明结构)。
此数据结构表示单个线程的状态。唯一的公共数据成员是
-
PyInterpreterState *interp¶
此线程的解释器状态。
-
PyInterpreterState *interp¶
-
void PyEval_InitThreads()¶
- 属于 稳定 ABI 的一部分。
已弃用的函数,不执行任何操作。
在 Python 3.6 及更早的版本中,如果 GIL 不存在,此函数会创建它。
在 3.9 版本中更改:该函数现在不执行任何操作。
在 3.7 版本中更改:此函数现在由
Py_Initialize()
调用,因此您不必再自己调用它。在 3.2 版本中更改:此函数不能在
Py_Initialize()
之前调用。自 3.9 版本起已弃用。
-
PyThreadState *PyEval_SaveThread()¶
- 属于 稳定 ABI 的一部分。
释放全局解释器锁(如果已创建),并将线程状态重置为
NULL
,返回之前的线程状态(不为NULL
)。如果锁已创建,则当前线程必须已获取该锁。
-
void PyEval_RestoreThread(PyThreadState *tstate)¶
- 属于 稳定 ABI 的一部分。
获取全局解释器锁(如果已创建),并将线程状态设置为 tstate,该值不能为
NULL
。如果锁已创建,则当前线程不得获取该锁,否则会导致死锁。注意
在运行时正在完成时从线程调用此函数将终止该线程,即使该线程不是由 Python 创建的。您可以使用
Py_IsFinalizing()
或sys.is_finalizing()
来检查解释器是否正在完成过程中,以避免不必要的终止。
-
PyThreadState *PyThreadState_Get()¶
- 属于 稳定 ABI 的一部分。
返回当前线程状态。必须持有全局解释器锁。当当前线程状态为
NULL
时,这将发出致命错误(以便调用者不必检查NULL
)。
-
PyThreadState *PyThreadState_GetUnchecked()¶
类似于
PyThreadState_Get()
,但如果为 NULL,则不会导致进程因致命错误而终止。调用者负责检查结果是否为 NULL。3.13 版本新增: 在 Python 3.5 到 3.12 中,该函数是私有的,被称为
_PyThreadState_UncheckedGet()
。
-
PyThreadState *PyThreadState_Swap(PyThreadState *tstate)¶
- 属于 稳定 ABI 的一部分。
将当前线程状态与参数 tstate 给定的线程状态交换,tstate 可以为
NULL
。必须持有全局解释器锁,并且不会释放该锁。
以下函数使用线程局部存储,与子解释器不兼容
-
PyGILState_STATE PyGILState_Ensure()¶
- 属于 稳定 ABI 的一部分。
确保当前线程已准备好调用 Python C API,无论 Python 的当前状态或全局解释器锁的状态如何。只要每个调用都与对
PyGILState_Release()
的调用相匹配,一个线程可以根据需要多次调用此函数。通常,只要在 Release() 之前将线程状态恢复到之前的状态,就可以在PyGILState_Ensure()
和PyGILState_Release()
调用之间使用其他与线程相关的 API。例如,正常使用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)¶
- 属于 稳定 ABI 的一部分。
释放之前获取的任何资源。在此调用之后,Python 的状态将与相应的
PyGILState_Ensure()
调用之前的状态相同(但通常此状态对于调用者是未知的,因此使用 GILState API)。每次调用
PyGILState_Ensure()
都必须与同一线程上的PyGILState_Release()
调用相匹配。
-
PyThreadState *PyGILState_GetThisThreadState()¶
- 属于 稳定 ABI 的一部分。
获取此线程的当前线程状态。如果在当前线程上没有使用过 GILState API,则可能返回
NULL
。请注意,主线程始终具有这样的线程状态,即使在主线程上没有进行自动线程状态调用也是如此。这主要是一个辅助/诊断函数。
-
int PyGILState_Check()¶
如果当前线程持有 GIL,则返回
1
,否则返回0
。可以随时从任何线程调用此函数。只有当它已初始化其 Python 线程状态并且当前持有 GIL 时,它才会返回1
。这主要是一个辅助/诊断函数。例如,在回调上下文或内存分配函数中,当知道 GIL 被锁定时,它可以允许调用者执行敏感操作或以其他方式表现不同,这可能很有用。在 3.4 版本中添加。
以下宏通常不带尾随分号使用;在 Python 源代码发行版中查找示例用法。
-
Py_BEGIN_ALLOW_THREADS¶
- 属于 稳定 ABI 的一部分。
此宏扩展为
{ PyThreadState *_save; _save = PyEval_SaveThread();
。请注意,它包含一个左大括号;它必须与后面的Py_END_ALLOW_THREADS
宏相匹配。有关此宏的进一步讨论,请参见上文。
-
Py_END_ALLOW_THREADS¶
- 属于 稳定 ABI 的一部分。
此宏扩展为
PyEval_RestoreThread(_save); }
。请注意,它包含一个右大括号;它必须与之前的Py_BEGIN_ALLOW_THREADS
宏相匹配。有关此宏的进一步讨论,请参见上文。
-
Py_BLOCK_THREADS¶
- 属于 稳定 ABI 的一部分。
此宏扩展为
PyEval_RestoreThread(_save);
:它等效于Py_END_ALLOW_THREADS
,但不包含右大括号。
-
Py_UNBLOCK_THREADS¶
- 属于 稳定 ABI 的一部分。
此宏扩展为
_save = PyEval_SaveThread();
:它等效于Py_BEGIN_ALLOW_THREADS
,但不包含左大括号和变量声明。
底层 API¶
以下所有函数都必须在 Py_Initialize()
之后调用。
在 3.7 版本中变更: Py_Initialize()
现在初始化 GIL。
-
PyInterpreterState *PyInterpreterState_New()¶
- 属于 稳定 ABI 的一部分。
创建一个新的解释器状态对象。全局解释器锁不需要持有,但如果需要序列化对此函数的调用,则可以持有。
引发一个审计事件
cpython.PyInterpreterState_New
,不带任何参数。
-
void PyInterpreterState_Clear(PyInterpreterState *interp)¶
- 属于 稳定 ABI 的一部分。
重置解释器状态对象中的所有信息。必须持有全局解释器锁。
引发一个审计事件
cpython.PyInterpreterState_Clear
,不带任何参数。
-
void PyInterpreterState_Delete(PyInterpreterState *interp)¶
- 属于 稳定 ABI 的一部分。
销毁一个解释器状态对象。全局解释器锁不需要持有。解释器状态必须已通过先前对
PyInterpreterState_Clear()
的调用重置。
-
PyThreadState *PyThreadState_New(PyInterpreterState *interp)¶
- 属于 稳定 ABI 的一部分。
创建一个属于给定解释器对象的新的线程状态对象。全局解释器锁不需要持有,但如果需要序列化对此函数的调用,则可以持有。
-
void PyThreadState_Clear(PyThreadState *tstate)¶
- 属于 稳定 ABI 的一部分。
重置线程状态对象中的所有信息。必须持有全局解释器锁。
在 3.9 版本中变更: 此函数现在调用
PyThreadState.on_delete
回调。之前,这发生在PyThreadState_Delete()
中。在 3.13 版本中变更:
PyThreadState.on_delete
回调已移除。
-
void PyThreadState_Delete(PyThreadState *tstate)¶
- 属于 稳定 ABI 的一部分。
销毁一个线程状态对象。全局解释器锁不需要持有。线程状态必须已通过先前对
PyThreadState_Clear()
的调用重置。
-
void PyThreadState_DeleteCurrent(void)¶
销毁当前线程状态并释放全局解释器锁。与
PyThreadState_Delete()
一样,必须持有全局解释器锁。线程状态必须已通过先前对PyThreadState_Clear()
的调用重置。
-
PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)¶
- 自 3.10 版本起为稳定 ABI的一部分。
获取 Python 线程状态 tstate 的当前帧。
返回一个强引用。如果当前没有执行帧,则返回
NULL
。另请参阅
PyEval_GetFrame()
。tstate 不得为
NULL
。在 3.9 版本中添加。
-
uint64_t PyThreadState_GetID(PyThreadState *tstate)¶
- 自 3.10 版本起为稳定 ABI的一部分。
获取 Python 线程状态 tstate 的唯一线程状态标识符。
tstate 不得为
NULL
。在 3.9 版本中添加。
-
PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)¶
- 自 3.10 版本起为稳定 ABI的一部分。
获取 Python 线程状态 tstate 的解释器。
tstate 不得为
NULL
。在 3.9 版本中添加。
-
void PyThreadState_EnterTracing(PyThreadState *tstate)¶
暂停 Python 线程状态 tstate 中的跟踪和性能分析。
使用
PyThreadState_LeaveTracing()
函数恢复它们。在 3.11 版本中添加。
-
void PyThreadState_LeaveTracing(PyThreadState *tstate)¶
恢复 Python 线程状态 tstate 中被
PyThreadState_EnterTracing()
函数暂停的跟踪和性能分析。另请参阅
PyEval_SetTrace()
和PyEval_SetProfile()
函数。在 3.11 版本中添加。
-
PyInterpreterState *PyInterpreterState_Get(void)¶
- 自 3.9 版本起为稳定 ABI的一部分。
获取当前解释器。
如果当前没有 Python 线程状态或没有当前解释器,则发出致命错误。它不能返回 NULL。
调用者必须持有 GIL。
在 3.9 版本中添加。
-
int64_t PyInterpreterState_GetID(PyInterpreterState *interp)¶
- 自 3.7 版本起为稳定 ABI的一部分。
返回解释器的唯一 ID。如果执行此操作时出现任何错误,则返回
-1
并设置错误。调用者必须持有 GIL。
在 3.7 版本中添加。
-
PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)¶
- 自 3.8 版本起,属于 稳定 ABI 的一部分。
返回一个字典,可在其中存储特定于解释器的数据。如果此函数返回
NULL
,则没有引发异常,并且调用方应假定没有可用的特定于解释器的字典。这不能替代
PyModule_GetState()
,扩展应该使用它来存储特定于解释器的状态信息。3.8 版本中新增。
-
typedef PyObject *(*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)¶
帧评估函数的类型。
throwflag 参数由生成器的
throw()
方法使用:如果非零,则处理当前异常。在 3.9 版本中变更: 该函数现在接受一个 tstate 参数。
在 3.11 版本中变更: frame 参数从
PyFrameObject*
更改为_PyInterpreterFrame*
。
-
_PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp)¶
获取帧评估函数。
参见 PEP 523 “向 CPython 添加帧评估 API”。
在 3.9 版本中添加。
-
void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)¶
设置帧评估函数。
参见 PEP 523 “向 CPython 添加帧评估 API”。
在 3.9 版本中添加。
-
PyObject *PyThreadState_GetDict()¶
- 返回值:借用的引用。属于 稳定 ABI 的一部分。
返回一个字典,扩展可以在其中存储线程特定的状态信息。每个扩展都应该使用一个唯一的键来在该字典中存储状态。当没有当前线程状态可用时,调用此函数是可以的。如果此函数返回
NULL
,则不会引发异常,并且调用者应该假定没有可用的当前线程状态。
-
int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)¶
- 属于 稳定 ABI 的一部分。
在线程中异步引发异常。id 参数是目标线程的线程 id;exc 是要引发的异常对象。此函数不窃取对 exc 的任何引用。为了防止幼稚的误用,您必须编写自己的 C 扩展来调用此函数。必须在持有 GIL 的情况下调用。返回修改的线程状态数;这通常是一个,但如果找不到线程 id,则为零。如果 exc 是
NULL
,则清除该线程的待处理异常(如果有)。这不会引发任何异常。在 3.7 版本中变更: id 参数的类型从 long 更改为 unsigned long。
-
void PyEval_AcquireThread(PyThreadState *tstate)¶
- 属于 稳定 ABI 的一部分。
获取全局解释器锁,并将当前线程状态设置为 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)¶
- 属于 稳定 ABI 的一部分。
将当前线程状态重置为
NULL
并释放全局解释器锁。该锁必须先前已创建,并且必须由当前线程持有。tstate 参数不能为NULL
,仅用于检查它是否表示当前线程状态 - 如果不是,则会报告致命错误。PyEval_SaveThread()
是一个更高级别的函数,它始终可用(即使线程尚未初始化)。
子解释器支持¶
虽然在大多数情况下,您只会嵌入单个 Python 解释器,但在某些情况下,您需要在同一进程中,甚至在同一线程中创建多个独立的解释器。子解释器允许您执行此操作。
“主”解释器是在运行时初始化时创建的第一个解释器。它通常是进程中唯一的 Python 解释器。与子解释器不同,主解释器具有独特的进程全局责任,如信号处理。它还负责运行时初始化期间的执行,并且通常是运行时最终化期间的活动解释器。PyInterpreterState_Main()
函数返回指向其状态的指针。
您可以使用 PyThreadState_Swap()
函数在子解释器之间切换。您可以使用以下函数创建和销毁它们
-
type PyInterpreterConfig¶
包含配置子解释器的大多数参数的结构。它的值仅在
Py_NewInterpreterFromConfig()
中使用,并且永远不会被运行时修改。在 3.12 版本中添加。
结构字段
-
int use_main_obmalloc¶
如果此值为
0
,则子解释器将使用其自己的“对象”分配器状态。否则,它将使用(共享)主解释器的状态。如果此值为
0
,则check_multi_interp_extensions
必须为1
(非零)。如果此值为1
,则gil
不能为PyInterpreterConfig_OWN_GIL
。
-
int allow_fork¶
如果此值为
0
,则运行时将不支持在任何子解释器当前处于活动状态的线程中 fork 进程。否则,fork 操作不受限制。请注意,当 fork 操作被禁用时,
subprocess
模块仍然有效。
-
int allow_exec¶
如果此值为
0
,则运行时将不支持在任何子解释器当前处于活动状态的线程中通过 exec (例如os.execv()
) 替换当前进程。否则,exec 操作不受限制。请注意,当 exec 操作被禁用时,
subprocess
模块仍然有效。
-
int allow_daemon_threads¶
如果此值为
0
,则子解释器的threading
模块将不会创建守护线程。否则,允许创建守护线程(只要allow_threads
为非零值)。
-
int check_multi_interp_extensions¶
如果此值为
0
,则可以在任何子解释器当前处于活动状态的线程中导入所有扩展模块,包括旧的(单阶段初始化)模块。否则,只能导入多阶段初始化扩展模块(请参见 PEP 489)。(另请参见Py_mod_multiple_interpreters
。)如果
use_main_obmalloc
为0
,则此值必须为1
(非零)。
-
int gil¶
此值决定子解释器的 GIL 的操作。它可以是以下值之一
-
PyInterpreterConfig_DEFAULT_GIL¶
使用默认选择 (
PyInterpreterConfig_SHARED_GIL
)。
-
PyInterpreterConfig_SHARED_GIL¶
使用(共享)主解释器的 GIL。
-
PyInterpreterConfig_OWN_GIL¶
使用子解释器自己的 GIL。
如果此值为
PyInterpreterConfig_OWN_GIL
,则PyInterpreterConfig.use_main_obmalloc
必须为0
。-
PyInterpreterConfig_DEFAULT_GIL¶
-
int use_main_obmalloc¶
-
PyStatus Py_NewInterpreterFromConfig(PyThreadState **tstate_p, const PyInterpreterConfig *config)¶
创建一个新的子解释器。这为执行 Python 代码提供了一个(几乎)完全独立的环境。特别是,新解释器拥有所有导入模块的单独、独立版本,包括基本模块
builtins
、__main__
和sys
。加载的模块表(sys.modules
)和模块搜索路径(sys.path
)也是独立的。新环境没有sys.argv
变量。它具有新的标准 I/O 流文件对象sys.stdin
、sys.stdout
和sys.stderr
(但是这些都指向相同的底层文件描述符)。给定的 config 控制解释器初始化的选项。
成功后,tstate_p 将设置为新子解释器中创建的第一个线程状态。此线程状态在当前线程状态中创建。请注意,没有创建实际线程;请参阅下面的线程状态讨论。如果新解释器的创建不成功,则 tstate_p 将设置为
NULL
;不会设置异常,因为异常状态存储在当前线程状态中,并且可能没有当前线程状态。与所有其他 Python/C API 函数一样,在调用此函数之前必须持有全局解释器锁,并且在它返回时仍然持有。同样,在进入时必须设置当前线程状态。成功后,返回的线程状态将设置为当前状态。如果子解释器是用自己的 GIL 创建的,则调用解释器的 GIL 将被释放。当函数返回时,当前线程将持有新解释器的 GIL,并且先前解释器的 GIL 将在此处保持释放状态。
在 3.12 版本中添加。
当子解释器彼此隔离,并限制某些功能时,它们最有效。
PyInterpreterConfig config = { .use_main_obmalloc = 0, .allow_fork = 0, .allow_exec = 0, .allow_threads = 1, .allow_daemon_threads = 0, .check_multi_interp_extensions = 1, .gil = PyInterpreterConfig_OWN_GIL, }; PyThreadState *tstate = NULL; PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config); if (PyStatus_Exception(status)) { Py_ExitStatusException(status); }
请注意,配置仅在短时间内使用,并且不会被修改。在初始化期间,配置的值会转换为各种
PyInterpreterState
值。配置的只读副本可以存储在PyInterpreterState
的内部。扩展模块在(子)解释器之间共享,如下所示
对于使用多阶段初始化的模块,例如
PyModule_FromDefAndSpec()
,会为每个解释器创建和初始化单独的模块对象。只有 C 级别的静态和全局变量在这些模块对象之间共享。对于使用单阶段初始化的模块,例如
PyModule_Create()
,首次导入特定扩展时,会正常初始化它,并保存其模块字典的(浅)副本。当另一个(子)解释器导入相同的扩展时,会初始化一个新模块,并用此副本的内容填充它;不会调用扩展的init
函数。因此,模块字典中的对象最终会在(子)解释器之间共享,这可能会导致不必要的行为(请参阅下面的 错误和注意事项)。请注意,这与通过调用
Py_FinalizeEx()
和Py_Initialize()
完全重新初始化解释器后导入扩展时发生的情况不同;在这种情况下,会再次调用扩展的initmodule
函数。与多阶段初始化一样,这意味着只有 C 级别的静态和全局变量在这些模块之间共享。
-
PyThreadState *Py_NewInterpreter(void)¶
- 属于 稳定 ABI 的一部分。
创建一个新的子解释器。这本质上只是对
Py_NewInterpreterFromConfig()
的一个封装,使用一个保留现有行为的配置。结果是一个非隔离的子解释器,它与主解释器共享 GIL,允许 fork/exec,允许守护线程,并允许单阶段初始化模块。
-
void Py_EndInterpreter(PyThreadState *tstate)¶
- 属于 稳定 ABI 的一部分。
销毁由给定线程状态表示的(子)解释器。给定的线程状态必须是当前线程状态。请参阅下面的线程状态讨论。当调用返回时,当前线程状态为
NULL
。与此解释器关联的所有线程状态都将被销毁。在调用此函数之前,必须持有目标解释器使用的全局解释器锁。当它返回时,不持有 GIL。Py_FinalizeEx()
将销毁所有在此时未被显式销毁的子解释器。
每个解释器一个 GIL¶
使用 Py_NewInterpreterFromConfig()
,你可以创建一个与其他解释器完全隔离的子解释器,包括拥有自己的 GIL。这种隔离最重要的好处是,这样的解释器可以在不被其他解释器阻塞或阻塞任何其他解释器的情况下执行 Python 代码。因此,当运行 Python 代码时,单个 Python 进程可以真正利用多个 CPU 核心。隔离还鼓励采用与仅使用线程不同的并发方法。(参见 PEP 554。)
使用隔离的解释器需要警惕地维护这种隔离。这尤其意味着在没有关于线程安全的保证的情况下,不要共享任何对象或可变状态。即使是原本不可变的对象(例如,None
,(1, 5)
)通常也无法共享,因为引用计数。一种简单但效率较低的方法是在某些状态(或对象)的所有使用周围使用全局锁。或者,通过将它们设为 不朽的,可以使有效的不可变对象(如整数或字符串)在引用计数方面保持安全。事实上,内置单例、小整数和许多其他内置对象已经完成了这一点。
如果你保持隔离,那么你将可以访问正确的多核计算,而不会出现自由线程带来的复杂性。未能保持隔离会将你暴露在自由线程的全部后果中,包括竞争和难以调试的崩溃。
除此之外,使用多个隔离解释器的主要挑战之一是如何在它们之间安全地通信(不破坏隔离)和高效地通信。运行时和 stdlib 尚未提供任何标准的通信方法。未来的 stdlib 模块将有助于减少保持隔离的工作量,并公开在解释器之间通信(和共享)数据的有效工具。
在 3.12 版本中添加。
错误和注意事项¶
由于子解释器(和主解释器)是同一进程的一部分,它们之间的隔离并不完美——例如,使用低级文件操作(如 os.close()
)它们可以(意外或恶意地)影响彼此打开的文件。由于扩展在(子)解释器之间共享的方式,某些扩展可能无法正常工作;当使用单阶段初始化或(静态)全局变量时,这种情况尤其可能发生。可以将在一个子解释器中创建的对象插入到另一个(子)解释器的命名空间中;如果可能,应避免这种情况。
应特别注意避免在子解释器之间共享用户定义的函数、方法、实例或类,因为此类对象执行的导入操作可能会影响错误的(子)解释器的已加载模块字典。同样重要的是避免共享可以访问上述对象的对象。
另请注意,将此功能与 PyGILState_*
API 结合使用是微妙的,因为这些 API 假设 Python 线程状态和操作系统级线程之间存在双射关系,而子解释器的存在会破坏这种假设。强烈建议不要在匹配的 PyGILState_Ensure()
和 PyGILState_Release()
调用之间切换子解释器。此外,使用这些 API 以允许从非 Python 创建的线程调用 Python 代码的扩展(例如 ctypes
)在使用子解释器时可能会被破坏。
异步通知¶
提供了一种机制,可以向主解释器线程发出异步通知。这些通知采用函数指针和 void 指针参数的形式。
-
int Py_AddPendingCall(int (*func)(void*), void *arg)¶
- 属于 稳定 ABI 的一部分。
计划一个函数从主解释器线程调用。成功时,返回
0
,并且将 func 排队以在主线程中调用。失败时,返回-1
,而不设置任何异常。成功排队后,func 将最终从主解释器线程中调用,参数为 arg。它将相对于正常运行的 Python 代码异步调用,但满足这两个条件
func 必须在成功时返回
0
,在失败时返回-1
并设置异常。不会中断 func 来递归执行另一个异步通知,但如果释放全局解释器锁,它仍然可能被中断以切换线程。此函数不需要当前线程状态即可运行,也不需要全局解释器锁。
要在子解释器中调用此函数,调用方必须持有 GIL。否则,可以将函数 func 安排为从错误的解释器调用。
警告
这是一个低级函数,仅在非常特殊的情况下有用。不能保证 func 会尽快被调用。如果主线程正忙于执行系统调用,则在系统调用返回之前不会调用 func。此函数通常不适合从任意 C 线程调用 Python 代码。而是使用 PyGILState API。
在版本 3.1 中添加。
在 3.9 版本中更改: 如果此函数在子解释器中调用,则现在安排从子解释器而不是从主解释器调用函数 func。每个子解释器现在都有自己的计划调用列表。
性能分析和跟踪¶
Python 解释器为附加性能分析和执行跟踪工具提供了一些底层支持。这些用于性能分析、调试和覆盖率分析工具。
此 C 接口允许性能分析或跟踪代码避免通过 Python 级可调用对象调用的开销,而是直接进行 C 函数调用。该工具的基本属性没有改变;该接口允许为每个线程安装跟踪函数,并且报告给跟踪函数的基本事件与以前版本中报告给 Python 级跟踪函数的事件相同。
-
typedef 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 的含义
总是
Py_None
。由
sys.exc_info()
返回的异常信息。总是
Py_None
。返回给调用者的值,如果是由异常引起的则为
NULL
。正在被调用的函数对象。
正在被调用的函数对象。
正在被调用的函数对象。
总是
Py_None
。
-
int PyTrace_CALL¶
当报告对函数或方法的新调用,或新进入生成器时,作为
Py_tracefunc
函数的 what 参数的值。请注意,生成器函数的迭代器的创建不会报告,因为没有控制转移到相应帧中的 Python 字节码。
-
int PyTrace_EXCEPTION¶
当引发异常时,作为
Py_tracefunc
函数的 what 参数的值。当在执行帧中设置异常后处理任何字节码之后,使用此 what 值调用回调函数。这样做的效果是,当异常传播导致 Python 堆栈展开时,当异常传播时,将在返回到每个帧时调用回调。只有跟踪函数会接收到这些事件;分析器不需要它们。
-
int PyTrace_LINE¶
当报告行号事件时,传递给
Py_tracefunc
函数(但不是分析函数)的 what 参数的值。可以通过将该帧上的f_trace_lines
设置为 0 来禁用该帧的行号事件。
-
int PyTrace_RETURN¶
当调用即将返回时,作为
Py_tracefunc
函数的 what 参数的值。
-
int PyTrace_C_CALL¶
当即将调用 C 函数时,作为
Py_tracefunc
函数的 what 参数的值。
-
int PyTrace_C_EXCEPTION¶
当 C 函数引发异常时,作为
Py_tracefunc
函数的 what 参数的值。
-
int PyTrace_C_RETURN¶
当 C 函数返回时,作为
Py_tracefunc
函数的 what 参数的值。
-
int PyTrace_OPCODE¶
当即将执行新的操作码时,作为
Py_tracefunc
函数(但不是分析函数)的 what 参数的值。默认情况下不会发出此事件:必须通过将帧上的f_trace_opcodes
设置为 1 来显式请求此事件。
-
void PyEval_SetProfile(Py_tracefunc func, PyObject *obj)¶
将分析器函数设置为 func。obj 参数作为其第一个参数传递给该函数,可以是任何 Python 对象,也可以是
NULL
。如果分析函数需要维护状态,则为每个线程使用不同的 obj 值可以提供一个方便且线程安全的位置来存储它。将为所有受监控的事件调用分析函数,除了PyTrace_LINE
、PyTrace_OPCODE
和PyTrace_EXCEPTION
。另请参阅
sys.setprofile()
函数。调用者必须持有 GIL。
-
void PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *obj)¶
类似于
PyEval_SetProfile()
,但在当前解释器中所有正在运行的线程中设置分析函数,而不是仅在当前线程上设置。调用者必须持有 GIL。
与
PyEval_SetProfile()
一样,此函数会忽略在所有线程中设置分析函数时引发的任何异常。
在 3.12 版本中添加。
-
void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)¶
将跟踪函数设置为 func。这类似于
PyEval_SetProfile()
,但跟踪函数会接收行号事件和每操作码事件,但不会接收任何与 C 函数对象被调用相关的事件。使用PyEval_SetTrace()
注册的任何跟踪函数都不会接收PyTrace_C_CALL
、PyTrace_C_EXCEPTION
或PyTrace_C_RETURN
作为 what 参数的值。另请参阅
sys.settrace()
函数。调用者必须持有 GIL。
-
void PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *obj)¶
与
PyEval_SetTrace()
类似,但在属于当前解释器的所有正在运行的线程中设置跟踪函数,而不是仅在当前线程中设置。调用者必须持有 GIL。
与
PyEval_SetTrace()
一样,此函数会忽略在所有线程中设置跟踪函数时引发的任何异常。
在 3.12 版本中添加。
引用跟踪¶
3.13 版本中新增。
-
typedef int (*PyRefTracer)(PyObject*, int event, void *data)¶
使用
PyRefTracer_SetTracer()
注册的跟踪函数的类型。第一个参数是一个刚创建的 Python 对象(当 event 设置为PyRefTracer_CREATE
时)或即将被销毁的对象(当 event 设置为PyRefTracer_DESTROY
时)。data 参数是在调用PyRefTracer_SetTracer()
时提供的不透明指针。
3.13 版本中新增。
-
int PyRefTracer_CREATE¶
当 Python 对象已创建时,
PyRefTracer
函数的 event 参数的值。
-
int PyRefTracer_DESTROY¶
当 Python 对象已被销毁时,
PyRefTracer
函数的 event 参数的值。
-
int PyRefTracer_SetTracer(PyRefTracer tracer, void *data)¶
注册引用跟踪函数。当创建新的 Python 对象或即将销毁对象时,将调用此函数。如果提供了 data,则它必须是一个不透明指针,该指针将在调用跟踪函数时提供。成功时返回
0
。发生错误时,设置异常并返回-1
。请注意,跟踪函数不得在内部创建 Python 对象,否则调用将是可重入的。跟踪器也不得清除任何现有异常或设置异常。每次调用跟踪函数时,都会持有 GIL。
调用此函数时必须持有 GIL。
3.13 版本中新增。
-
PyRefTracer PyRefTracer_GetTracer(void **data)¶
获取注册的引用跟踪函数以及在调用
PyRefTracer_SetTracer()
时注册的不透明数据指针的值。如果未注册任何跟踪器,此函数将返回 NULL,并将 data 指针设置为 NULL。调用此函数时必须持有 GIL。
3.13 版本中新增。
高级调试器支持¶
这些函数仅供高级调试工具使用。
-
PyInterpreterState *PyInterpreterState_Head()¶
返回所有此类对象列表头部的解释器状态对象。
-
PyInterpreterState *PyInterpreterState_Main()¶
返回主解释器状态对象。
-
PyInterpreterState *PyInterpreterState_Next(PyInterpreterState *interp)¶
从所有此类对象的列表中返回 interp 之后的下一个解释器状态对象。
-
PyThreadState *PyInterpreterState_ThreadHead(PyInterpreterState *interp)¶
返回指向与解释器 interp 关联的线程列表中第一个
PyThreadState
对象的指针。
-
PyThreadState *PyThreadState_Next(PyThreadState *tstate)¶
从属于同一
PyInterpreterState
对象的所有此类对象的列表中返回 tstate 之后的下一个线程状态对象。
线程局部存储支持¶
Python 解释器为线程局部存储 (TLS) 提供底层支持,该支持包装了底层本机 TLS 实现,以支持 Python 级线程局部存储 API (threading.local
)。CPython C 级 API 类似于 pthreads 和 Windows 提供的 API:使用线程键和函数来关联每个线程的 void* 值。
调用这些函数时,不需要持有 GIL;它们提供自己的锁定。
请注意,Python.h
不包含 TLS API 的声明,您需要包含 pythread.h
才能使用线程局部存储。
注意
这些 API 函数均不代表 void* 值处理内存管理。您需要自己分配和释放它们。如果 void* 值恰好是 PyObject*,则这些函数也不会对它们执行引用计数操作。
线程特定存储 (TSS) API¶
引入 TSS API 是为了取代在 CPython 解释器中使用现有 TLS API。此 API 使用新的类型 Py_tss_t
而不是 int 来表示线程键。
在 3.7 版本中添加。
另请参阅
“CPython 中线程局部存储的新 C-API” (PEP 539)
-
type Py_tss_t¶
此数据结构表示线程键的状态,其定义可能取决于底层 TLS 实现,并且它具有一个表示键初始化状态的内部字段。此结构中没有公共成员。
当未定义 Py_LIMITED_API 时,允许通过
Py_tss_NEEDS_INIT
静态分配此类型。
-
Py_tss_NEEDS_INIT¶
此宏展开为
Py_tss_t
变量的初始化器。 请注意,在使用了 Py_LIMITED_API 的情况下,此宏将不会被定义。
动态分配¶
在用 Py_LIMITED_API 构建的扩展模块中,需要动态分配 Py_tss_t
,因为此类型的静态分配是不可能的,因为其实现方式在构建时是不透明的。
-
Py_tss_t *PyThread_tss_alloc()¶
- 自 3.7 版本起为稳定 ABI的一部分。
返回一个与使用
Py_tss_NEEDS_INIT
初始化后的值具有相同状态的值,或者在动态分配失败的情况下返回NULL
。
-
void PyThread_tss_free(Py_tss_t *key)¶
- 自 3.7 版本起为稳定 ABI的一部分。
释放由
PyThread_tss_alloc()
分配的给定 key ,并在此之前先调用PyThread_tss_delete()
来确保所有关联的线程局部变量都已被取消赋值。 如果 key 参数为NULL
,则这是一个空操作。注意
一个被释放的键会变成悬空指针。 你应该将该键重置为
NULL
。
方法¶
这些函数的参数 key 不能为 NULL
。 此外,如果给定的 Py_tss_t
未通过 PyThread_tss_create()
初始化,则 PyThread_tss_set()
和 PyThread_tss_get()
的行为是未定义的。
-
int PyThread_tss_is_created(Py_tss_t *key)¶
- 自 3.7 版本起为稳定 ABI的一部分。
如果给定的
Py_tss_t
已通过PyThread_tss_create()
初始化,则返回一个非零值。
-
int PyThread_tss_create(Py_tss_t *key)¶
- 自 3.7 版本起为稳定 ABI的一部分。
成功初始化 TSS 键时返回零值。 如果 key 参数指向的值不是通过
Py_tss_NEEDS_INIT
初始化的,则行为是未定义的。 此函数可以对同一个键重复调用 – 对已初始化的键调用它是一个空操作,并立即返回成功。
-
void PyThread_tss_delete(Py_tss_t *key)¶
- 自 3.7 版本起为稳定 ABI的一部分。
销毁一个 TSS 键以忘记跨所有线程与该键关联的值,并将该键的初始化状态更改为未初始化。 销毁的键可以通过
PyThread_tss_create()
再次初始化。 此函数可以对同一个键重复调用 – 对已销毁的键调用它是一个空操作。
线程局部存储 (TLS) API¶
自 3.7 版本起已弃用: 此 API 已被 线程特定存储 (TSS) API 取代。
注意
此版本的 API 不支持本机 TLS 键的定义方式不能安全地强制转换为 int
的平台。 在此类平台上,PyThread_create_key()
将立即返回失败状态,并且其他 TLS 函数在此类平台上都将为空操作。
由于上面提到的兼容性问题,不应在新代码中使用此版本的 API。
同步原语¶
C-API 提供基本的互斥锁。
-
type PyMutex¶
互斥锁。
PyMutex
应该初始化为零,以表示未锁定状态。 例如PyMutex mutex = {0};
PyMutex
的实例不应复制或移动。PyMutex
的内容和地址都是有意义的,它必须保持在内存中的固定可写位置。注意
PyMutex
当前占用一个字节,但该大小应被认为是不稳定的。 大小可能会在未来的 Python 版本中更改,而不会有弃用期。3.13 版本中新增。
-
void PyMutex_Lock(PyMutex *m)¶
锁定互斥锁 m。如果另一个线程已经锁定了它,则调用线程将阻塞,直到互斥锁被解锁。在阻塞期间,如果持有 GIL,线程将临时释放它。
3.13 版本中新增。
Python 临界区 API¶
临界区 API 为 自由线程 CPython 上的每个对象锁提供了一个死锁避免层。它们旨在取代对 全局解释器锁 的依赖,并且在具有全局解释器锁的 Python 版本中是空操作。
临界区通过在调用 PyEval_SaveThread()
期间隐式挂起活动临界区并释放锁来避免死锁。当调用 PyEval_RestoreThread()
时,将恢复最近的临界区,并重新获取其锁。这意味着临界区 API 提供的保证比传统锁弱 - 它们之所以有用,是因为它们的行为类似于 GIL。
宏使用的函数和结构暴露出来,以便在 C 宏不可用的情况下使用。它们应该只按照给定的宏展开中使用。请注意,结构的尺寸和内容可能会在未来的 Python 版本中发生变化。
注意
需要一次锁定两个对象的操作必须使用 Py_BEGIN_CRITICAL_SECTION2
。你*不能*使用嵌套的临界区来一次锁定多个对象,因为内部临界区可能会挂起外部临界区。此 API 不提供一次锁定两个以上对象的方法。
示例用法
static PyObject *
set_field(MyObject *self, PyObject *value)
{
Py_BEGIN_CRITICAL_SECTION(self);
Py_SETREF(self->field, Py_XNewRef(value));
Py_END_CRITICAL_SECTION();
Py_RETURN_NONE;
}
在上面的示例中,Py_SETREF
调用 Py_DECREF
,后者可以通过对象的释放函数调用任意代码。临界区 API 通过允许运行时在终结器触发的代码阻塞并调用 PyEval_SaveThread()
时临时挂起临界区,从而避免了由于重入和锁顺序导致的潜在死锁。
-
Py_BEGIN_CRITICAL_SECTION(op)¶
获取对象 op 的每个对象锁,并开始一个临界区。
在自由线程构建中,此宏展开为
{ PyCriticalSection _py_cs; PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))
在默认构建中,此宏展开为
{
。3.13 版本中新增。
-
Py_END_CRITICAL_SECTION()¶
结束临界区并释放每个对象锁。
在自由线程构建中,此宏展开为
PyCriticalSection_End(&_py_cs); }
在默认构建中,此宏展开为
}
。3.13 版本中新增。
-
Py_BEGIN_CRITICAL_SECTION2(a, b)¶
获取对象 a 和 b 的每个对象锁,并开始一个临界区。锁以一致的顺序(先最低地址)获取,以避免锁顺序死锁。
在自由线程构建中,此宏展开为
{ PyCriticalSection2 _py_cs2; PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))
在默认构建中,此宏展开为
{
。3.13 版本中新增。
-
Py_END_CRITICAL_SECTION2()¶
结束临界区并释放每个对象锁。
在自由线程构建中,此宏展开为
PyCriticalSection2_End(&_py_cs2); }
在默认构建中,此宏展开为
}
。3.13 版本中新增。