初始化,终结和线程¶
请参阅 Python 初始化配置 。
在Python初始化之前¶
在一个植入了 Python 的应用程序中,Py_Initialize()
函数必须在任何其他 Python/C API 函数之前被调用;例外的只有个别函数和 全局配置变量。
在初始化Python之前,可以安全地调用以下函数:
配置函数:
信息函数:
工具
内存分配器:
备注
The following functions should not be called before
Py_Initialize()
: Py_EncodeLocale()
, Py_GetPath()
,
Py_GetPrefix()
, Py_GetExecPrefix()
,
Py_GetProgramFullPath()
, Py_GetPythonHome()
,
and Py_GetProgramName()
.
全局配置变量¶
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_importlib
和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
错误处理句柄作用 filesystem encoding and error handler。如果
PYTHONLEGACYWINDOWSFSENCODING
环境变量被设为非空字符串则设为1
。更多详情请参阅 PEP 529。
可用性: Windows。
从 3.12 版起不建议使用,将在 3.14 版中移除.
-
int Py_LegacyWindowsStdioFlag¶
此 API 被保留用于向下兼容:应当改为设置
PyConfig.legacy_windows_stdio
,参见 Python 初始化配置。如果该旗标为非零值,则会使用
io.FileIO
而不是io._WindowsConsoleIO
作为sys
标准流。如果
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 初始化之前 了解少数的例外情况。
This initializes the table of loaded modules (
sys.modules
), and creates the fundamental modulesbuiltins
,__main__
andsys
. It also initializes the module search path (sys.path
). It does not setsys.argv
; use the newPyConfig
API of the Python Initialization Configuration for that. This is a no-op when called for a second time (without callingPy_FinalizeEx()
first). There is no return value; it is a fatal error if the initialization fails.使用
Py_InitializeFromConfig()
函数自定义 Python 初始化配置。备注
在 Windows 上,将控制台模式从
O_TEXT
改为O_BINARY
,这还将影响使用 C 运行时的非 Python 的控制台使用。
-
void Py_InitializeEx(int initsigs)¶
- 属于 稳定 ABI.
如果 initsigs 为
1
则该函数的工作方式与Py_Initialize()
类似。 如果 initsigs 为0
,它将跳过信号处理句柄的初始化注册,这在嵌入 Python 时可能会很有用处。使用
Py_InitializeFromConfig()
函数自定义 Python 初始化配置。
-
int Py_IsInitialized()¶
- 属于 稳定 ABI.
如果 Python 解释器已初始化,则返回真值(非零);否则返回假值(零)。 在调用
Py_FinalizeEx()
之后,此函数将返回假值直到Py_Initialize()
再次被调用。
-
int Py_IsFinalizing()¶
- 属于 稳定 ABI 自 3.13 版开始.
Return true (non-zero) if the main Python interpreter is shutting down. Return false (zero) otherwise.
在 3.13 版本加入.
-
int Py_FinalizeEx()¶
- 属于 稳定 ABI 自 3.6 版开始.
撤销
Py_Initialize()
所做的所有初始化操作和后续对 Python/C API 函数的使用,并销毁自上次调用Py_Initialize()
以来创建但尚未销毁的所有子解释器(参见下文Py_NewInterpreter()
一节)。 在理想情况下,这会释放 Python 解释器分配的所有内存。 当第二次调用时(在未再次调用Py_Initialize()
的情况下),这将不执行任何操作。 正常情况下返回值是0
。 如果在最终化(刷新缓冲数据)过程中出现错误,则返回-1
。提供此函数的原因有很多。嵌入应用程序可能希望重新启动Python,而不必重新启动应用程序本身。从动态可加载库(或DLL)加载Python解释器的应用程序可能希望在卸载DLL之前释放Python分配的所有内存。在搜索应用程序内存泄漏的过程中,开发人员可能希望在退出应用程序之前释放Python分配的所有内存。
程序问题和注意事项: 模块和模块中对象的销毁是按随机顺序进行的;这可能导致依赖于其他对象(甚至函数)或模块的析构器(即
__del__()
方法)出错。 Python 所加载的动态加载扩展模块不会被卸载。 Python 解释器所分配的少量内存可能不会被释放(如果发现内存泄漏,请报告问题)。 对象间循环引用所占用的内存不会被释放。 扩展模块所分配的某些内存可能不会被释放。 如果某些扩展的初始化例程被调用多次它们可能无法正常工作;如果应用程序多次调用了Py_Initialize()
和Py_FinalizeEx()
就可能发生这种情况。引发一个 审计事件
cpython._PySys_ClearAuditHooks
,不附带任何参数。在 3.6 版本加入.
-
void Py_Finalize()¶
- 属于 稳定 ABI.
这是一个不考虑返回值的
Py_FinalizeEx()
的向下兼容版本。
进程级参数¶
-
wchar_t *Py_GetProgramName()¶
- 属于 稳定 ABI.
Return the program name set with
PyConfig.program_name
, or the default. The returned string points into static storage; the caller should not modify its value.此函数不应在
Py_Initialize()
之前被调用,否则将返回NULL
。在 3.10 版本发生变更: 现在如果它在
Py_Initialize()
之前被调用将返回NULL
。从 3.13 版起不建议使用,将在 3.15 版中移除: Get
sys.executable
instead.
-
wchar_t *Py_GetPrefix()¶
- 属于 稳定 ABI.
Return the prefix for installed platform-independent files. This is derived through a number of complicated rules from the program name set with
PyConfig.program_name
and some environment variables; for example, if the program name is'/usr/local/bin/python'
, the prefix is'/usr/local'
. The returned string points into static storage; the caller should not modify its value. This corresponds to the prefix variable in the top-levelMakefile
and the--prefix
argument to the configure script at build time. The value is available to Python code assys.prefix
. It is only useful on Unix. See also the next function.此函数不应在
Py_Initialize()
之前被调用,否则将返回NULL
。在 3.10 版本发生变更: 现在如果它在
Py_Initialize()
之前被调用将返回NULL
。从 3.13 版起不建议使用,将在 3.15 版中移除: Get
sys.prefix
instead.
-
wchar_t *Py_GetExecPrefix()¶
- 属于 稳定 ABI.
Return the exec-prefix for installed platform-dependent files. This is derived through a number of complicated rules from the program name set with
PyConfig.program_name
and some environment variables; for example, if the program name is'/usr/local/bin/python'
, the exec-prefix is'/usr/local'
. The returned string points into static storage; the caller should not modify its value. This corresponds to the exec_prefix variable in the top-levelMakefile
and the--exec-prefix
argument to the configure script at build time. The value is available to Python code assys.exec_prefix
. It is only useful on Unix.背景:当依赖于平台的文件(如可执行文件和共享库)是安装于不同的目录树中的时候 exec-prefix 将会不同于 prefix。 在典型的安装中,依赖于平台的文件可能安装于 the
/usr/local/plat
子目录树而独立于平台的文件可能安装于/usr/local
。总而言之,平台是一组硬件和软件资源的组合,例如所有运行 Solaris 2.x 操作系统的 Sparc 机器会被视为相同平台,但运行 Solaris 2.x 的 Intel 机器是另一种平台,而运行 Linux 的 Intel 机器又是另一种平台。 相同操作系统的不同主要发布版通常也会构成不同的平台。 非 Unix 操作系统的情况又有所不同;这类系统上的安装策略差别巨大因此 prefix 和 exec-prefix 是没有意义的,并将被设为空字符串。 请注意已编译的 Python 字节码是独立于平台的(但并不独立于它们编译时所使用的 Python 版本!)
系统管理员知道如何配置 mount 或 automount 程序以在平台间共享
/usr/local
而让/usr/local/plat
成为针对不同平台的不同文件系统。此函数不应在
Py_Initialize()
之前被调用,否则将返回NULL
。在 3.10 版本发生变更: 现在如果它在
Py_Initialize()
之前被调用将返回NULL
。从 3.13 版起不建议使用,将在 3.15 版中移除: Get
sys.exec_prefix
instead.
-
wchar_t *Py_GetProgramFullPath()¶
- 属于 稳定 ABI.
Return the full program name of the Python executable; this is computed as a side-effect of deriving the default module search path from the program name (set by
PyConfig.program_name
). The returned string points into static storage; the caller should not modify its value. The value is available to Python code assys.executable
.此函数不应在
Py_Initialize()
之前被调用,否则将返回NULL
。在 3.10 版本发生变更: 现在如果它在
Py_Initialize()
之前被调用将返回NULL
。从 3.13 版起不建议使用,将在 3.15 版中移除: Get
sys.executable
instead.
-
wchar_t *Py_GetPath()¶
- 属于 稳定 ABI.
Return the default module search path; this is computed from the program name (set by
PyConfig.program_name
) and some environment variables. The returned string consists of a series of directory names separated by a platform dependent delimiter character. The delimiter character is':'
on Unix and macOS,';'
on Windows. The returned string points into static storage; the caller should not modify its value. The listsys.path
is initialized with this value on interpreter startup; it can be (and usually is) modified later to change the search path for loading modules.此函数不应在
Py_Initialize()
之前被调用,否则将返回NULL
。在 3.10 版本发生变更: 现在如果它在
Py_Initialize()
之前被调用将返回NULL
。从 3.13 版起不建议使用,将在 3.15 版中移除: Get
sys.path
instead.
-
const char *Py_GetVersion()¶
- 属于 稳定 ABI.
返回 Python 解释器的版本。 这将为如下形式的字符串
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
第一个单词(到第一个空格符为止)是当前的 Python 版本;前面的字符是以点号分隔的主要和次要版本号。 返回的字符串将指向静态存储;调用方不应修改其值。 该值将以
sys.version
的名称供 Python 代码使用。另请参阅
Py_Version
常量。
-
const char *Py_GetPlatform()¶
- 属于 稳定 ABI.
返回当前平台的平台标识符。 在 Unix 上,这将以操作系统的“官方”名称为基础,转换为小写形式,再加上主版本号;例如,对于 Solaris 2.x,或称 SunOS 5.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
中获取该值。
-
wchar_t *Py_GetPythonHome()¶
- 属于 稳定 ABI.
Return the default "home", that is, the value set by
PyConfig.home
, or the value of thePYTHONHOME
environment variable if it is set.此函数不应在
Py_Initialize()
之前被调用,否则将返回NULL
。在 3.10 版本发生变更: 现在如果它在
Py_Initialize()
之前被调用将返回NULL
。从 3.13 版起不建议使用,将在 3.15 版中移除: Get
PyConfig.home
orPYTHONHOME
environment variable instead.
线程状态和全局解释器锁¶
Python 解释器不是完全线程安全的。 为了支持多线程的 Python 程序,设置了一个全局锁,称为 global interpreter lock 或 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 之前或之后需要获取或重置的附加(非 Python)锁。 需要使用 OS 工具例如 pthread_atfork()
来完成同样的事情。 此外,在扩展或嵌入 Python 时,直接调用 fork()
而不是通过 os.fork()
(并返回到或调用至 Python 中) 调用可能会导致某个被 fork 之后失效的线程所持有的 Python 内部锁发生死锁。 PyOS_AfterFork_Child()
会尝试重置必要的锁,但并不总是能够做到。
所有其他线程都将结束这一事实也意味着 CPython 的运行时状态必须妥善清理,os.fork()
就是这样做的。 这意味着最终化归属于当前解释器的所有其他 PyThreadState
对象以及所有其他 PyInterpreterState
对象。 由于这一点以及 "main" 解释器 的特殊性质,fork()
应当只在该解释器 的 "main" 线程中被调用,而 CPython 全局运行时最初就是在该线程中初始化的。 只有当 exec()
将随后立即被调用的情况是唯一的例外。
高阶 API¶
这些是在编写 C 扩展代码或在嵌入 Python 解释器时最常用的类型和函数:
-
type PyInterpreterState¶
- 属于 受限 API (作为不透明的结构体).
该数据结构代表多个合作线程所共享的状态。 属于同一解释器的线程将共享其模块管理以及其他一些内部条目。 该结构体中不包含公有成员。
最初归属于不同解释器的线程不会共享任何东西,但进程状态如可用内存、打开的文件描述符等等除外。 全局解释器锁也会被所有线程共享,无论它们归属于哪个解释器。
-
type PyThreadState¶
- 属于 受限 API (作为不透明的结构体).
该数据结构代表单个线程的状态。 唯一的公有数据成员为:
-
PyInterpreterState *interp¶
该线程的解释器状态。
-
PyInterpreterState *interp¶
-
PyThreadState *PyEval_SaveThread()¶
- 属于 稳定 ABI.
释放全局解释器锁 (如果已创建) 并将线程状态重置为
NULL
,返回之前的线程状态 (不为NULL
)。 如果锁已被创建,则当前线程必须已获取到它。
-
void PyEval_RestoreThread(PyThreadState *tstate)¶
- 属于 稳定 ABI.
获取全局解释器锁 (如果已创建) 并将线程状态设为 tstate,它必须不为
NULL
。 如果锁已被创建,则当前线程必须尚未获取它,否则将发生死锁。备注
Calling this function from a thread when the runtime is finalizing will terminate the thread, even if the thread was not created by Python. You can use
Py_IsFinalizing()
orsys.is_finalizing()
to check if the interpreter is in process of being finalized before calling this function to avoid unwanted termination.
-
PyThreadState *PyThreadState_Get()¶
- 属于 稳定 ABI.
返回当前线程状态。 全局解释器锁必须被持有。 在当前状态为
NULL
时,这将发出一个致命错误 (这样调用方将无须检查是否为NULL
)。See also
PyThreadState_GetUnchecked()
.
-
PyThreadState *PyThreadState_GetUnchecked()¶
Similar to
PyThreadState_Get()
, but don't kill the process with a fatal error if it is NULL. The caller is responsible to check if the result is NULL.在 3.13 版本加入: In Python 3.5 to 3.12, the function was private and known as
_PyThreadState_UncheckedGet()
.
-
PyThreadState *PyThreadState_Swap(PyThreadState *tstate)¶
- 属于 稳定 ABI.
交换当前线程状态与由参数 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 代码。 执行失败将导致致命级错误。
备注
Calling this function from a thread when the runtime is finalizing will terminate the thread, even if the thread was not created by Python. You can use
Py_IsFinalizing()
orsys.is_finalizing()
to check if the interpreter is in process of being finalized before calling this function to avoid unwanted termination.
-
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()
中的。
-
void PyThreadState_Delete(PyThreadState *tstate)¶
- 属于 稳定 ABI.
销毁线程状态对象。 不需要持有全局解释器锁。 线程状态必须使用之前对
PyThreadState_Clear()
的调用来重置。
-
void PyThreadState_DeleteCurrent(void)¶
销毁当前线程状态并释放全局解释器锁。 与
PyThreadState_Delete()
类似,不需要持有全局解释器锁。 线程状态必须已使用之前对PyThreadState_Clear()
调用来重置。
-
PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)¶
- 属于 稳定 ABI 自 3.10 版开始.
获取 Python 线程状态 tstate 的当前帧。
返回一个 strong reference。 如果没有当前执行的帧则返回
NULL
。另请参阅
PyEval_GetFrame()
。tstate 必须不为
NULL
。在 3.9 版本加入.
-
uint64_t PyThreadState_GetID(PyThreadState *tstate)¶
- 属于 稳定 ABI 自 3.10 版开始.
获取 Python 线程状态 tstate 的唯一线程状态标识符。
tstate 必须不为
NULL
。在 3.9 版本加入.
-
PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)¶
- 属于 稳定 ABI 自 3.10 版开始.
获取 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)¶
- 属于 稳定 ABI 自 3.9 版开始.
获取当前解释器。
如果不存在当前 Python 线程状态或不存在当前解释器则将发出致命级错误信号。 它无法返回 NULL。
呼叫者必须持有GIL。
在 3.9 版本加入.
-
int64_t PyInterpreterState_GetID(PyInterpreterState *interp)¶
- 属于 稳定 ABI 自 3.7 版开始.
返回解释器的唯一 ID。 如果执行过程中发生任何错误则将返回
-1
并设置错误。呼叫者必须持有GIL。
在 3.7 版本加入.
-
PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)¶
- 属于 稳定 ABI 自 3.8 版开始.
返回一个存储解释器专属数据的字典。 如果此函数返回
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 "Adding a frame evaluation API to CPython"。
在 3.9 版本加入.
-
void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)¶
设置帧评估函数。
请参阅 PEP 523 "Adding a frame evaluation API to CPython"。
在 3.9 版本加入.
-
PyObject *PyThreadState_GetDict()¶
- 返回值:借入的引用。 属于 稳定 ABI.
返回一个扩展可以在其中存储线程专属状态信息的字典。 每个扩展都应当使用一个独有的键用来在该字典中存储状态。 在没有可用的当前线程状态时也可以调用此函数。 如果此函数返回
NULL
,则还没有任何异常被引发并且调用方应当假定没有可用的当前线程状态。
-
int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)¶
- 属于 稳定 ABI.
在一个线程中异步地引发异常。 id 参数是目标线程的线程 id;exc 是要引发的异常对象。 该函数不会窃取任何对 exc 的引用。 为防止随意滥用,你必须编写你自己的 C 扩展来调用它。 调用时必须持有 GIL。 返回已修改的线程状态数量;该值通常为一,但如果未找到线程 id 则会返回 0。 如果 exc 为``NULL``,则会清除线程的待处理异常(如果存在)。 这将不会引发异常。
在 3.7 版本发生变更: id 形参的类型已从 long 变为 unsigned long。
-
void PyEval_AcquireThread(PyThreadState *tstate)¶
- 属于 稳定 ABI.
获取全局解释器锁并将当前线程状态设为 tstate,它必须不为
NULL
。 锁必须在此之前已被创建。 如果该线程已获取锁,则会发生死锁。备注
Calling this function from a thread when the runtime is finalizing will terminate the thread, even if the thread was not created by Python. You can use
Py_IsFinalizing()
orsys.is_finalizing()
to check if the interpreter is in process of being finalized before calling this function to avoid unwanted termination.在 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 = Py_NewInterpreterFromConfig(&config);
请注意该配置只会被短暂使用而不会被修改。 在初始化期间配置的值会被转换成各种
PyInterpreterState
值。 配置的只读副本可以被内部存储于PyInterpreterState
中。扩展模块将以如下方式在(子)解释器之间共享:
对于使用多阶段初始化的模块 ,例如
PyModule_FromDefAndSpec()
,将为每个解释器创建并初始化一个单独的模块对象。 只有 C 层级的静态和全局变量能在这些模块 对象之间共享。对于使用单阶段初始化的模块,例如
PyModule_Create()
,当特定扩展被首次导入时,它将被正常初始化,并会保存其模块字典的一个 (浅) 拷贝。 当同一扩展被另一个 (子) 解释器导入时,将初始化一个新模块并填充该拷贝的内容;扩展的init
函数不会被调用。 因此模块字典中的对象最终会被 (子) 解释器所共享,这可能会导致预期之外的行为 (参见下文的 Bugs and caveats)。请注意这不同于在调用
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)。
Using an isolated interpreter requires vigilance in preserving that
isolation. That especially means not sharing any objects or mutable
state without guarantees about thread-safety. Even objects that are
otherwise immutable (e.g. None
, (1, 5)
) can't normally be shared
because of the refcount. One simple but less-efficient approach around
this is to use a global lock around all use of some state (or object).
Alternately, effectively immutable objects (like integers or strings)
can be made safe in spite of their refcounts by making them immortal.
In fact, this has been done for the builtin singletons, small integers,
and a number of other builtin objects.
如果你能保持隔离状态那么你将能获得真正的多核计算能力而不会遇到自由线程所带来的复杂性。 如果未能保持隔离状态那么你将面对自由线程所带来的全部后果,包括线程竞争和难以调试的崩溃。
除此之外,使用多个相互隔离的解释器的一个主要挑战是如何在它们之间安全 (不破坏隔离状态)、高效地进行通信。 运行时和标准库还没有为此提供任何标准方式。 未来的标准库模块将会帮助减少保持隔离状态所需的工作量并为解释器之间的数据通信(和共享)公开有效的工具。
在 3.12 版本加入.
错误和警告¶
由于子解释器 (以及主解释器) 都是同一个进程的组成部分,它们之间的隔离状态并非完美 --- 举例来说,使用低层级的文件操作如 os.close()
时它们可能 (无意或恶意地) 影响它们各自打开的文件。 由于 (子) 解释器之间共享扩展的方式,某些扩展可能无法正常工作;在使用单阶段初始化或者 (静态) 全局变量时尤其如此。 在一个子解释器中创建的对象有可能被插入到另一个 (子) 解释器的命名空间中;这种情况应当尽可能地避免。
应当特别注意避免在子解释器之间共享用户自定义的函数、方法、实例或类,因为由这些对象执行的导入 操作可能会影响错误的已加载模块的 (子) 解释器的字典。 同样重要的一点是应当避免共享可被上述对象访问的对象 。
还要注意的一点是将此功能与 PyGILState_*
API 结合使用是很微妙的,因为这些 API 会假定 Python线程状态与操作系统级线程之间存在双向投影关系,而子解释器的存在打破了这一假定。 强烈建议你不要在一对互相匹配的 PyGILState_Ensure()
和 PyGILState_Release()
调用之间切换子解释器。 此外,使用这些 API 以允许从非 Python 创建的线程调用 Python 代码的扩展 (如 ctypes
) 在使用子解释器时很可能会出现问题。
异步通知¶
提供了一种向主解释器线程发送异步通知的机制。 这些通知将采用函数指针和空指针参数的形式。
-
int Py_AddPendingCall(int (*func)(void*), void *arg)¶
- 属于 稳定 ABI.
将一个函数加入从主解释器线程调用的计划任务。 成功时,将返回
0
并将 func 加入要被主线程调用的等待队列。 失败时,将返回-1
但不会设置任何异常。当成功加入队列后,func 将 最终 附带参数 arg 被主解释器线程调用。 对于正常运行的 Python 代码来说它将被异步地调用,但要同时满足以下两个条件:
位于 bytecode 的边界上;
主线程持有 global interpreter lock (因此 func 可以使用完整的 C API)。
func 必须在成功时返回
0
,或在失败时返回-1
并设置一个异常集合。 func 不会被中断来递归地执行另一个异步通知,但如果全局解释器锁被释放则它仍可被中断以切换线程。此函数的运行不需要当前线程状态,也不需要全局解释器锁。
要在子解释器中调用函数,调用方必须持有 GIL。 否则,函数 func 可能会被安排给错误的解释器来调用。
警告
这是一个低层级函数,只在非常特殊的情况下有用。 不能保证 func 会尽快被调用。 如果主线程忙于执行某个系统调用,func 将不会在系统调用返回之前被调用。 此函数 通常 不适合 从任意 C 线程调用 Python 代码。 作为替代,请使用 PyGILStateAPI。
在 3.9 版本发生变更: 如果此函数在子解释器中被调用,则函数 func 将被安排在子解释器中调用,而不是在主解释器中调用。现在每个子解释器都有自己的计划调用列表。
在 3.1 版本加入.
分析和跟踪¶
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 版本加入.
高级调试器支持¶
这些函数仅供高级调试工具使用。
-
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 所提供的类似:使用一个线程键和函数来为每个线程关联一个 void* 值。
当调用这些函数时 无须 持有 GIL;它们会提供自己的锁机制。
请注意 Python.h
并不包括 TLS API 的声明,你需要包括 pythread.h
来使用线程本地存储。
备注
这些 API 函数都不会为 void* 的值处理内存管理问题。 你需要自己分配和释放它们。 如果 void* 值碰巧为 PyObject*,这些函数也不会对它们执行引用计数操作。
线程专属存储 (TSS) API¶
引入 TSSAPI 是为了取代 CPython 解释器中现有 TLS API 的使用。 该 API 使用一个新类型 Py_tss_t
而不是 int 来表示线程键。
在 3.7 版本加入.
参见
"A New C-API for Thread-Local Storage in CPython" (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_tss_t
的动态分配,在使用 Py_LIMITED_API 编译的扩展模块中是必须的,在这些模块由于此类型的实现在编译时是不透明的因此它不可能静态分配。
-
Py_tss_t *PyThread_tss_alloc()¶
- 属于 稳定 ABI 自 3.7 版开始.
返回一个与使用
Py_tss_NEEDS_INIT
初始化的值的状态相同的值,或者当动态分配失败时则返回NULL
。
-
void PyThread_tss_free(Py_tss_t *key)¶
- 属于 稳定 ABI 自 3.7 版开始.
在首次调用
PyThread_tss_delete()
以确保任何相关联的线程局部变量已被撤销赋值之后释放由PyThread_tss_alloc()
所分配的给定的 key。 如果 key 参数为NULL
则这将无任何操作。备注
被释放的 key 将变成一个悬空指针。 你应当将 key 重置为
NULL
。
方法¶
这些函数的形参 key 不可为 NULL
。 并且,如果给定的 Py_tss_t
还未被 PyThread_tss_create()
初始化则 PyThread_tss_set()
和 PyThread_tss_get()
的行为将是未定义的。
-
int PyThread_tss_is_created(Py_tss_t *key)¶
- 属于 稳定 ABI 自 3.7 版开始.
如果给定的
Py_tss_t
已通过has been initialized byPyThread_tss_create()
被初始化则返回一个非零值。
-
int PyThread_tss_create(Py_tss_t *key)¶
- 属于 稳定 ABI 自 3.7 版开始.
当成功初始化一个 TSS 键时将返回零值。 如果 key 参数所指向的值未被
Py_tss_NEEDS_INIT
初始化则其行为是未定义的。 此函数可在相同的键上重复调用 -- 在已初始化的键上调用它将不执行任何操作并立即成功返回。
-
void PyThread_tss_delete(Py_tss_t *key)¶
- 属于 稳定 ABI 自 3.7 版开始.
销毁一个 TSS 键以便在所有线程中遗忘与该键相关联的值,并将该键的初始化状态改为未初始化的。 已销毁的键可以通过
PyThread_tss_create()
再次被初始化。 此函数可以在同一个键上重复调用 -- 但在一个已被销毁的键上调用将是无效的。
线程本地存储 (TLS) API¶
自 3.7 版本弃用: 此 API 已被 线程专属存储 (TSS) API 所取代。
备注
这个 API 版本不支持原生 TLS 键采用无法被安全转换为 int
的的定义方式的平台。 在这样的平台上,PyThread_create_key()
将立即返回一个失败状态,并且其他 TLS 函数在这样的平台上也都无效。
由于上面提到的兼容性问题,不应在新代码中使用此版本的API。