初始化、终结和线程¶
也见 Python Initialization Configuration .
在python初始化之前¶
在嵌入python的应用程序中, Py_Initialize()
在使用任何其他python/c api函数之前必须调用函数;除了一些函数和 global configuration variables .
在初始化python之前,可以安全地调用以下函数:
配置功能:
信息功能:
公用事业:
内存分配器:
注解
以下功能 不应调用 之前 Py_Initialize()
: Py_EncodeLocale()
, Py_GetPath()
, Py_GetPrefix()
, Py_GetExecPrefix()
, Py_GetProgramFullPath()
, Py_GetPythonHome()
, Py_GetProgramName()
和 PyEval_InitThreads()
.
全局配置变量¶
python有用于全局配置的变量来控制不同的特性和选项。默认情况下,这些标志由 command line options .
当某个标志由某个选项设置时,该标志的值是该选项设置的次数。例如, -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
用于初始化机密hash种子的环境变量。
-
int Py_IgnoreEnvironmentFlag¶
忽略所有
PYTHON*
环境变量,例如PYTHONPATH
和PYTHONHOME
,可以设置。
-
int Py_InspectFlag¶
当脚本作为第一个参数或
-c
使用选项,在执行脚本或命令后进入交互模式,即使在sys.stdin
似乎不是终端。由
-i
期权与期权PYTHONINSPECT
环境变量。
-
int Py_LegacyWindowsFSEncodingFlag¶
如果该标志为非零,则使用
mbcs
编码使用replace
错误处理程序,而不是使用surrogatepass
错误处理程序,用于 filesystem encoding and error handler 。设置为
1
如果PYTHONLEGACYWINDOWSFSENCODING
环境变量设置为非空字符串。见 PEP 529 了解更多详细信息。
Availability :Windows。
-
int Py_LegacyWindowsStdioFlag¶
如果标志非零,则使用
io.FileIO
而不是WindowsConsoleIO
对于sys
标准流。设置为
1
如果PYTHONLEGACYWINDOWSSTDIO
环境变量设置为非空字符串。见 PEP 528 了解更多详细信息。
Availability :Windows。
-
int Py_NoUserSiteDirectory¶
不要添加
user site-packages directory
到sys.path
.由
-s
和-I
选项,以及PYTHONNOUSERSITE
环境变量。
-
int Py_OptimizeFlag¶
由
-O
期权与期权PYTHONOPTIMIZE
环境变量。
-
int Py_UnbufferedStdioFlag¶
强制取消缓冲stdout和stderr流。
由
-u
期权与期权PYTHONUNBUFFERED
环境变量。
-
int Py_VerboseFlag¶
每次初始化模块时打印一条消息,显示从中加载模块的位置(文件名或内置模块)。如果大于或等于
2
,为搜索模块时选中的每个文件打印一条消息。还提供有关退出时模块清理的信息。由
-v
期权与期权PYTHONVERBOSE
环境变量。
初始化和完成解释器¶
-
void Py_Initialize()¶
初始化python解释器。在嵌入python的应用程序中,应该在使用任何其他python/c api函数之前调用此函数;请参见 Before Python Initialization 为数不多的例外。
这将初始化已加载模块的表 (
sys.modules
)并创建基本模块builtins
,__main__
和sys
. 它还初始化模块搜索路径 (sys.path
)它没有设置sys.argv
使用PySys_SetArgvEx()
为此。这是第二次调用时的禁止操作(不调用Py_FinalizeEx()
首先)。没有返回值;如果初始化失败,则是一个致命错误。注解
在Windows上,更改控制台模式
O_TEXT
到O_BINARY
这也将影响使用C运行时的控制台的非python使用。
-
void Py_InitializeEx(int initsigs)¶
此函数的工作方式如下
Py_Initialize()
如果 因特西格斯 是1
.如果 因特西格斯 是0
它跳过了信号处理程序的初始化注册,这在嵌入Python时可能很有用。
-
int Py_IsInitialized()¶
初始化python解释器后返回true(非零),否则返回false(零)。后
Py_FinalizeEx()
如果调用,则返回false,直到Py_Initialize()
再次调用。
-
int Py_FinalizeEx()¶
撤消由执行的所有初始化
Py_Initialize()
以及随后使用的python/c api函数,并销毁所有子解释器(请参见Py_NewInterpreter()
以下)自上次调用以来创建但尚未销毁的Py_Initialize()
.理想情况下,这将释放由Python解释器分配的所有内存。这是第二次调用时的禁止操作(不调用Py_Initialize()
还是第一个)。通常返回值为0
. 如果在定稿(刷新缓冲数据)过程中出现错误,-1
返回。提供此功能的原因有很多。嵌入应用程序可能希望重新启动python而不必重新启动应用程序本身。从动态可加载库(或dll)加载了python解释器的应用程序可能希望在卸载dll之前释放python分配的所有内存。在搜寻应用程序中的内存泄漏时,开发人员可能希望在退出应用程序之前释放python分配的所有内存。
错误和警告: 模块中的模块和对象的破坏是随机进行的;这可能导致析构函数 (
__del__()
方法)在依赖其他对象(甚至函数)或模块时失败。不会卸载由python加载的动态加载的扩展模块。python解释器分配的少量内存可能无法释放(如果发现泄漏,请报告)。对象之间循环引用中绑定的内存不会释放。扩展模块分配的某些内存可能无法释放。如果多次调用某些扩展的初始化例程,则它们可能无法正常工作;如果应用程序调用Py_Initialize()
和Py_FinalizeEx()
不止一次。提出一个 auditing event
cpython._PySys_ClearAuditHooks
没有参数。3.6 新版功能.
-
void Py_Finalize()¶
这是的向后兼容版本
Py_FinalizeEx()
忽略返回值。
全过程参数¶
-
int Py_SetStandardStreamEncoding(const char *encoding, const char *errors)¶
此函数应该在
Py_Initialize()
,如果它被调用。它指定与标准IO一起使用的编码和错误处理,其含义与中的相同。str.encode()
.它超越
PYTHONIOENCODING
值,并允许嵌入代码在环境变量不工作时控制IO编码。编码 和/或 错误 可能是
NULL
使用PYTHONIOENCODING
和/或默认值(取决于其他设置)。注意
sys.stderr
始终使用“backslashreplace”错误处理程序,而不考虑此(或任何其他)设置。如果
Py_FinalizeEx()
如果调用,则需要再次调用此函数,以影响后续对Py_Initialize()
.返回
0
如果成功,则为出错时的非零值(例如,在解释器已初始化后调用)。3.4 新版功能.
-
void Py_SetProgramName(const wchar_t *name)¶
此函数应该在
Py_Initialize()
第一次被调用,如果它被调用的话。它告诉解释器argv[0]
参数main()
程序的功能(转换为宽字符)。这是由Py_GetPath()
以及下面的一些其他函数来查找与解释器可执行文件相关的python运行时库。默认值为'python'
. 该参数应指向静态存储器中以零结尾的宽字符串,该字符串的内容在程序执行期间不会更改。python解释器中的任何代码都不会更改此存储的内容。使用
Py_DecodeLocale()
解码字节字符串以获取 wchar_* 字符串。
-
wchar *Py_GetProgramName()¶
返回用设置的程序名
Py_SetProgramName()
或默认值。返回的字符串指向静态存储;调用方不应修改其值。在此之前不应调用此函数
Py_Initialize()
,否则它将返回NULL
。在 3.10 版更改: 现在它又回来了
NULL
如果在此之前调用Py_Initialize()
。
-
wchar_t *Py_GetPrefix()¶
返回 前缀 用于安装的独立于平台的文件。这是通过许多复杂的规则从程序名集合中派生的
Py_SetProgramName()
以及一些环境变量;例如,如果程序名是'/usr/local/bin/python'
,前缀是'/usr/local'
. 返回的字符串指向静态存储;调用方不应修改其值。这对应于 prefix 顶层变量Makefile
以及--prefix
参数 configure 在生成时编写脚本。该值可用于python代码sys.prefix
.它只在Unix上有用。另请参见下一个函数。在此之前不应调用此函数
Py_Initialize()
,否则它将返回NULL
。在 3.10 版更改: 现在它又回来了
NULL
如果在此之前调用Py_Initialize()
。
-
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
.一般来说,平台是硬件和软件系列的组合,例如运行Solaris 2.x操作系统的SPARC机器被认为是相同的平台,但运行Solaris 2.x的Intel机器是另一个平台,运行Linux的Intel机器是另一个平台。同一操作系统的不同主要版本通常也会形成不同的平台。非UNIX操作系统是另一回事;这些系统上的安装策略是如此不同,以至于前缀和exec前缀毫无意义,并设置为空字符串。请注意,编译后的python字节码文件与平台无关(但与编译它们的python版本无关!).
系统管理员将知道如何配置 mount 或 automount 要共享的程序
/usr/local
在平台之间/usr/local/plat
对于每个平台都是不同的文件系统。在此之前不应调用此函数
Py_Initialize()
,否则它将返回NULL
。在 3.10 版更改: 现在它又回来了
NULL
如果在此之前调用Py_Initialize()
。
-
wchar_t *Py_GetProgramFullPath()¶
返回python可执行文件的完整程序名;这是从程序名(由
Py_SetProgramName()
以上)。返回的字符串指向静态存储;调用方不应修改其值。该值可用于python代码sys.executable
.在此之前不应调用此函数
Py_Initialize()
,否则它将返回NULL
。在 3.10 版更改: 现在它又回来了
NULL
如果在此之前调用Py_Initialize()
。
-
wchar_t *Py_GetPath()¶
返回默认的模块搜索路径;这是根据程序名(由
Py_SetProgramName()
以及一些环境变量。返回的字符串由一系列目录名组成,这些目录名由一个与平台相关的分隔符字符分隔。分隔符是':'
在Unix和Mac OS X上,';'
在Windows上。返回的字符串指向静态存储;调用方不应修改其值。名单sys.path
在解释器启动时用该值初始化;稍后可以(通常也可以)修改该值以更改加载模块的搜索路径。在此之前不应调用此函数
Py_Initialize()
,否则它将返回NULL
。在 3.10 版更改: 现在它又回来了
NULL
如果在此之前调用Py_Initialize()
。
-
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_* 字符串。路径参数是在内部复制的,因此调用方可以在调用完成后释放它。
在 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()
.如果 更新数据表 是零,这就是函数的全部功能。如果 更新数据表 为非零,函数还修改
sys.path
根据以下算法:如果传入了现有脚本的名称
argv[0]
,脚本所在目录的绝对路径是sys.path
.否则(即,如果 argc 是
0
或argv[0]
不指向现有的文件名),空字符串被附加到sys.path
,与当前工作目录的前置相同 ("."
)
使用
Py_DecodeLocale()
解码字节字符串以获取 wchar_* 字符串。注解
建议将python解释器嵌入的应用程序用于执行单个脚本传递以外的目的。
0
作为 更新数据表 和更新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()
具有 更新数据表 设置为1
除非 python 解释程序是用-I
.使用
Py_DecodeLocale()
解码字节字符串以获取 wchar_* 字符串。在 3.4 版更改: 这个 更新数据表 价值取决于
-I
.
-
void Py_SetPythonHome(const wchar_t *home)¶
设置默认的“home”目录,即标准python库的位置。见
PYTHONHOME
参数字符串的含义。参数应指向静态存储器中以零结尾的字符串,该字符串的内容在程序执行期间不会更改。python解释器中的任何代码都不会更改此存储的内容。
使用
Py_DecodeLocale()
解码字节字符串以获取 wchar_* 字符串。
-
w_char *Py_GetPythonHome()¶
返回默认的“home”,即以前调用设置的值
Py_SetPythonHome()
或PYTHONHOME
环境变量(如果已设置)。在此之前不应调用此函数
Py_Initialize()
,否则它将返回NULL
。在 3.10 版更改: 现在它又回来了
NULL
如果在此之前调用Py_Initialize()
。
线程状态和全局解释器锁¶
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,最后存储线程状态指针,然后才能开始使用tPython/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解决了这个问题 os.fork()
通过获取它在分叉之前内部使用的锁,然后释放它们。此外,它会重置任何 锁定对象 在孩子身上。在扩展或嵌入python时,无法通知python在fork之前或之后需要获取的额外(非python)锁。操作系统设施,如 pthread_atfork()
需要用来完成同样的事情。另外,当扩展或嵌入python时,调用 fork()
直接而不是通过 os.fork()
(并返回或调用python)可能会导致死锁,死锁是由一个线程持有的,该线程在fork之后已失效。 PyOS_AfterFork_Child()
尝试重置必要的锁,但不总是能够重置。
所有其他线程都消失的事实也意味着必须正确地清理CPython的运行时状态,这 os.fork()
做。这意味着完成所有其他 PyThreadState
属于当前解释器和所有其他解释器的对象 PyInterpreterState
物体。由于这一点和 "main" interpreter , fork()
只应在解释器的“主”线程中调用,CPython全局运行时最初是在该线程中初始化的。唯一的例外是 exec()
稍后将立即呼叫。
高级API¶
以下是编写C扩展代码或嵌入Python解释器时最常用的类型和函数:
-
type PyInterpreterState¶
此数据结构表示多个协作线程共享的状态。属于同一解释器的线程共享其模块管理和其他一些内部项。此结构中没有公共成员。
属于不同解释器的线程最初不共享任何内容,除了进程状态,如可用内存、打开文件描述符等。全局解释器锁也由所有线程共享,不管它们属于哪个解释器。
-
type PyThreadState¶
This data structure represents the state of a single thread. The only public data member is
interp
(PyInterpreterState*), which points to this thread's interpreter state.
-
void PyEval_InitThreads()¶
不推荐的函数,它什么也不做。
在Python3.6及更高版本中,如果GIL不存在,则此函数创建它。
在 3.9 版更改: 函数现在什么也不做。
在 3.7 版更改: 此函数现在由调用
Py_Initialize()
所以你不必再叫它自己了。在 3.2 版更改: 在此之前不能调用此函数
Py_Initialize()
不再。Deprecated since version 3.9, will be removed in version 3.11.
-
int PyEval_ThreadsInitialized()¶
返回一个非零值,如果
PyEval_InitThreads()
已被调用。可以在不保留gil的情况下调用此函数,因此可以在运行单线程时避免调用锁定API。在 3.7 版更改: 这个 GIL 现在由初始化
Py_Initialize()
.Deprecated since version 3.9, will be removed in version 3.11.
-
PyThreadState *PyEval_SaveThread()¶
释放全局解释器锁(如果已创建)并将线程状态重置为
NULL
,返回上一个线程状态(不是NULL
)如果已创建锁,则当前线程必须已获取该锁。
-
void PyEval_RestoreThread(PyThreadState *tstate)¶
获取全局解释器锁(如果已创建)并将线程状态设置为 泰州 ,不能是
NULL
. 如果已经创建了锁,则当前线程不能获取它,否则将导致死锁。注解
在运行时完成时从线程调用此函数将终止线程,即使该线程不是由python创建的。你可以使用
_Py_IsFinalizing()
或sys.is_finalizing()
在调用此函数之前检查解释器是否正在完成,以避免不必要的终止。
-
PyThreadState *PyThreadState_Get()¶
返回当前线程状态。必须持有全局解释器锁。当当前线程状态为
NULL
,这将发出一个致命错误(以便调用方不需要检查NULL
)
-
PyThreadState *PyThreadState_Swap(PyThreadState *tstate)¶
将当前线程状态与参数给定的线程状态交换 泰州 ,可能是
NULL
. 全局解释器锁必须保持不释放。
以下函数使用线程本地存储,与子解释程序不兼容:
-
PyGILState_STATE PyGILState_Ensure()¶
确保当前线程准备好调用python c api,而不管python或全局解释器锁的当前状态如何。只要每个调用与对的调用匹配,线程就可以根据需要多次调用它。
PyGILState_Release()
.通常,在PyGILState_Ensure()
和PyGILState_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()
调用(但通常调用方不知道此状态,因此使用Gilstate API)。每次召唤
PyGILState_Ensure()
必须通过调用匹配PyGILState_Release()
在同一条线上。
-
PyThreadState *PyGILState_GetThisThreadState()¶
获取此线程的当前线程状态。可能返回
NULL
如果当前线程上没有使用Gilstate API。注意,主线程总是有这样的线程状态,即使没有对主线程进行自动线程状态调用。这主要是辅助/诊断功能。
-
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()¶
创建新的解释器状态对象。不需要持有全局解释器锁,但如果需要序列化对此函数的调用,则可以持有全局解释器锁。
提出一个 auditing event
cpython.PyInterpreterState_New
没有参数。
-
void PyInterpreterState_Clear(PyInterpreterState *interp)¶
重置解释器状态对象中的所有信息。必须持有全局解释器锁。
提出一个 auditing event
cpython.PyInterpreterState_Clear
没有参数。
-
void PyInterpreterState_Delete(PyInterpreterState *interp)¶
销毁解释器状态对象。不需要持有全局解释器锁。解释器状态必须通过以前的调用重置
PyInterpreterState_Clear()
.
-
PyThreadState *PyThreadState_New(PyInterpreterState *interp)¶
创建属于给定解释器对象的新线程状态对象。不需要持有全局解释器锁,但如果需要序列化对此函数的调用,则可以持有全局解释器锁。
-
void PyThreadState_Clear(PyThreadState *tstate)¶
重置线程状态对象中的所有信息。必须持有全局解释器锁。
在 3.9 版更改: 此函数现在调用
PyThreadState.on_delete
回拨。以前,那发生在PyThreadState_Delete()
.
-
void PyThreadState_Delete(PyThreadState *tstate)¶
销毁线程状态对象。不需要持有全局解释器锁。线程状态必须已用以前的调用重置
PyThreadState_Clear()
.
-
void PyThreadState_DeleteCurrent(void)¶
销毁当前线程状态并释放全局解释器锁。就像
PyThreadState_Delete()
,不需要保持全局解释器锁。线程状态必须已用以前的调用重置PyThreadState_Clear()
.
-
PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)¶
获取Python线程状态的当前帧 泰州 .
返回一个 strong reference 。返回
NULL
如果当前没有帧正在执行,则返回。也见
PyEval_GetFrame()
.泰州 不得
NULL
.3.9 新版功能.
-
uint64_t PyThreadState_GetID(PyThreadState *tstate)¶
获取Python线程状态的唯一线程状态标识符 泰州 .
泰州 不得
NULL
.3.9 新版功能.
-
PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)¶
获取Python线程状态的解释器 泰州 .
泰州 不得
NULL
.3.9 新版功能.
-
PyInterpreterState *PyInterpreterState_Get(void)¶
找到当前的翻译。
如果没有当前的Python线程状态或当前的解释器,则发出致命错误。它不能返回空值。
打电话的人必须拿着电话。
3.9 新版功能.
-
int64_t PyInterpreterState_GetID(PyInterpreterState *interp)¶
返回解释器的唯一ID。如果执行此操作时出错,则
-1
返回并设置错误。打电话的人必须拿着电话。
3.7 新版功能.
-
PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)¶
返回一个可以存储解释程序特定数据的字典。如果此函数返回
NULL
然后就不会引发异常,调用方应该假设没有解释程序特定的dict可用。这不是替代
PyModule_GetState()
,应该使用哪些扩展来存储解释程序特定的状态信息。3.8 新版功能.
-
typedef PyObject *(*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *frame, int throwflag)¶
帧计算函数的类型。
这个 投掷旗 参数由
throw()
生成器方法:如果非零,则处理当前异常。在 3.9 版更改: 函数现在需要 泰州 参数。
-
_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()¶
- Return value: Borrowed reference.
返回扩展可以存储线程特定状态信息的字典。每个扩展都应该使用一个唯一的键来在字典中存储状态。当当前线程状态不可用时,可以调用此函数。如果此函数返回
NULL
,未引发异常,调用方应假定当前线程状态不可用。
-
int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)¶
在线程中异步引发异常。这个 id 参数是目标线程的线程ID; exc 是要引发的异常对象。此函数不会窃取对 exc . 为了防止天真的误用,您必须编写自己的C扩展来调用它。必须在有吉尔的情况下调用。返回修改的线程状态数;通常为1,但如果找不到线程ID,则为零。如果 exc 是
NULL
,线程的挂起异常(如果有)将被清除。这不会引发任何异常。在 3.7 版更改: 类型 id 参数更改自 long 到 unsigned long .
-
void PyEval_AcquireThread(PyThreadState *tstate)¶
获取全局解释器锁并将当前线程状态设置为 泰州 ,不能是
NULL
. 锁必须在前面创建。如果这个线程已经有了锁,就会发生死锁。注解
在运行时完成时从线程调用此函数将终止线程,即使该线程不是由python创建的。你可以使用
_Py_IsFinalizing()
或sys.is_finalizing()
在调用此函数之前检查解释器是否正在完成,以避免不必要的终止。在 3.8 版更改: 更新以符合
PyEval_RestoreThread()
,Py_END_ALLOW_THREADS()
和PyGILState_Ensure()
,并在解释器完成时终止当前线程(如果调用)。PyEval_RestoreThread()
是一个更高级别的函数,它始终可用(即使线程尚未初始化)。
-
void PyEval_ReleaseThread(PyThreadState *tstate)¶
将当前线程状态重置为
NULL
释放全局解释器锁。锁必须在前面创建,并且必须由当前线程持有。这个 泰州 参数,不能是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解释器,但在某些情况下,您需要在同一进程中甚至在同一线程中创建几个独立的解释器。口译员允许你这样做。
“main”解释器是运行时初始化时创建的第一个解释器。它通常是进程中唯一的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
返回;没有设置异常,因为异常状态存储在当前线程状态中,并且可能没有当前线程状态。(与所有其他python/c api函数一样,全局解释器锁必须在调用此函数之前保持,并且在返回时仍保持不变;但是,与大多数其他python/c api函数不同,在进入时不需要有当前的线程状态。)扩展模块在(子)口译员之间共享,如下所示:
对于使用多阶段初始化的模块,例如。
PyModule_FromDefAndSpec()
,为每个解释器创建并初始化一个单独的模块对象。这些模块对象之间只共享C级静态和全局变量。对于使用单相初始化的模块,例如。
PyModule_Create()
,第一次导入特定扩展时,它将正常初始化,并将其模块字典的(浅层)副本存储起来。当同一个扩展被另一个(子)解释器导入时,将初始化一个新模块,并用该副本的内容填充该模块;扩展的init
函数未被调用。因此,模块字典中的对象最终会在(子)解释器之间共享,这可能会导致不需要的行为(请参阅 Bugs and caveats 下面)。注意,这与通过调用
Py_FinalizeEx()
和Py_Initialize()
;在这种情况下,扩展initmodule
功能 is 又打电话来了。与多阶段初始化一样,这意味着这些模块之间只共享C级静态和全局变量。
-
void Py_EndInterpreter(PyThreadState *tstate)¶
销毁由给定线程状态表示的(子)解释器。给定的线程状态必须是当前线程状态。请参阅下面关于线程状态的讨论。当调用返回时,当前线程状态为
NULL
. 与此解释器关联的所有线程状态都将被销毁。(全局解释器锁必须在调用此函数之前保持不变,当它返回时仍保持不变。)Py_FinalizeEx()
将销毁当时未明确销毁的所有子解释程序。
错误和警告¶
因为子解释器(和主解释器)是同一过程的一部分,所以它们之间的隔离并不完美——例如,使用诸如 os.close()
它们可能(意外地或恶意地)影响彼此打开的文件。由于在(子)解释器之间共享扩展的方式,某些扩展可能无法正常工作;这在使用单相初始化或(静态)全局变量时尤其可能。可以将在一个子解释器中创建的对象插入到另一个(子)解释器的命名空间中;如果可能,应该避免这样做。
应特别注意避免在子解释器之间共享用户定义的函数、方法、实例或类,因为此类对象执行的导入操作可能会影响加载模块的错误(子)解释器字典。同样重要的是,避免共享从中可以访问上述内容的对象。
还要注意,将此功能与 PyGILState_* API很微妙,因为这些API假定在Python线程状态和操作系统级线程之间有一个双射,这一假设被子解释程序打破了。强烈建议您不要在一对匹配项之间切换子解释程序。 PyGILState_Ensure()
和 PyGILState_Release()
调用。此外,扩展(例如 ctypes
)当使用子解释器时,使用这些API允许从非Python创建的线程调用Python代码可能会被破坏。
非同步通知¶
提供了一种机制,用于向主解释器线程发出异步通知。这些通知采用函数指针和空指针参数的形式。
-
int Py_AddPendingCall(int (*func)(void*), void *arg)¶
安排从主解释器线程调用的函数。关于成功,
0
返回并 func 排队等待在主线程中调用。失败论-1
返回而不设置任何异常。成功排队后, func 将 最后 使用参数从主解释器线程调用 arg . 对于正常运行的python代码,将异步调用它,但同时满足以下两个条件:
在一 bytecode 边界;
主线程固定 global interpreter lock ( func 因此可以使用完整的C API)。
func 必须返回
0
关于成功,或-1
出现异常集失败时。 func 不会被中断以递归方式执行另一个异步通知,但是如果释放全局解释器锁,它仍然可以被中断以切换线程。这个函数不需要运行当前的线程状态,也不需要全局解释器锁。
要在子解释器中调用此函数,调用方必须持有GIL。否则,函数 func 可以安排从错误的解释程序调用。
警告
这是一个低级函数,只对非常特殊的情况有用。不能保证 func 将尽可能快地调用。如果主线程正忙于执行系统调用, func 在系统调用返回之前不会被调用。此功能通常是 not 适用于从任意C线程调用python代码。相反,使用 PyGILState API .
在 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 , 框架 是事件所属的帧对象, 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
. 如果profile函数需要保持状态,请使用不同的值 obj 为每根线提供了一个方便、安全的存放位置。配置文件函数用于除PyTrace_LINE
PyTrace_OPCODE
和PyTrace_EXCEPTION
.打电话的人必须按住 GIL .
-
void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)¶
将跟踪函数设置为 func . 这和
PyEval_SetProfile()
,但跟踪函数不接收行号事件和每个操作码事件,但不接收与正在调用的C函数对象相关的任何事件。使用注册的任何跟踪函数PyEval_SetTrace()
不会收到PyTrace_C_CALL
,PyTrace_C_EXCEPTION
或PyTrace_C_RETURN
作为 what 参数。打电话的人必须按住 GIL .
高级调试器支持¶
这些功能仅用于高级调试工具。
-
PyInterpreterState *PyInterpreterState_Head()¶
返回解释器状态对象,位于所有此类对象列表的开头。
-
PyInterpreterState *PyInterpreterState_Main()¶
返回主解释器状态对象。
-
PyInterpreterState *PyInterpreterState_Next(PyInterpreterState *interp)¶
之后返回下一个解释器状态对象 中间层 从所有这些对象的列表中。
-
PyThreadState *PyInterpreterState_ThreadHead(PyInterpreterState *interp)¶
将指针返回到第一个
PyThreadState
与解释器关联的线程列表中的对象 中间层 .
-
PyThreadState *PyThreadState_Next(PyThreadState *tstate)¶
返回之后的下一个线程状态对象 泰州 从属于同一对象的所有此类对象的列表中
PyInterpreterState
对象。
线程本地存储支持¶
python解释器为线程本地存储(tls)提供低级支持,该线程本地存储(tls)包装了底层的本机tls实现,以支持python级线程本地存储API。 (threading.local
)cpython C级API与pthreads和windows提供的API类似:使用线程键和函数关联 void* 每个线程的值。
吉尔 not 调用这些函数时需要保持;它们提供自己的锁。
注意 Python.h
不包括TLS API的声明,您需要包括 pythread.h
使用线程本地存储。
注解
这些API函数都不能代表 void* 价值观。您需要自己分配和解除分配它们。如果 void* 价值恰好是 PyObject* ,这些函数也不会对其执行refcount操作。
线程特定存储(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_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()
以确保已取消分配任何关联的线程局部变量。如果 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
.这个函数可以在同一个键上重复调用——在已经初始化的键上调用它是一个no op,并立即返回success。
-
void PyThread_tss_delete(Py_tss_t *key)¶
销毁TSS密钥以忘记所有线程中与该密钥关联的值,并将该密钥的初始化状态更改为未初始化。销毁的密钥可以通过
PyThread_tss_create()
. 这个函数可以在同一个键上重复调用——在已经销毁的键上调用它是一个禁忌。
线程本地存储(TLS)API¶
3.7 版后已移除: 此API被取代 Thread Specific Storage (TSS) API .
注解
此版本的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()¶