初始化,终结和Threads-Python / C API参考手册(Python教程)(参考资料)
初始化,终结和线程
在Python初始化之前
在嵌入Python的应用程序中,Py_Initialize()
必须在使用任何其他Python / C API函数之前调用函数;除了几个函数和全局配置变量.
在初始化Python之前,可以安全地调用以下函数:
- 配置函数:
PyImport_AppendInittab()
PyImport_ExtendInittab()
PyInitFrozenExtensions()
PyMem_SetAllocator()
PyMem_SetupDebugHooks()
PyObject_SetArenaAllocator()
Py_SetPath()
Py_SetProgramName()
Py_SetPythonHome()
Py_SetStandardStreamEncoding()
PySys_AddWarnOption()
PySys_AddXOption()
PySys_ResetWarnOptions()
- 信息函数:
PyMem_GetAllocator()
PyObject_GetArenaAllocator()
Py_GetBuildInfo()
Py_GetCompiler()
Py_GetCopyright()
Py_GetPlatform()
Py_GetVersion()
- 实用程序:
Py_DecodeLocale()
- 内存分配器:
PyMem_RawMalloc()
PyMem_RawRealloc()
PyMem_RawCalloc()
PyMem_RawFree()
以下函数
Python具有全局配置的变量来控制不同的功能和选项。默认情况下,这些标志由命令行选项.
当一个标志由一个选项设置时,该标志的值是该选项被设置的时间数。例如,-b
设置Py_BytesWarningFlag
到1和-bb
设置Py_BytesWarningFlag
到2.
Py_BytesWarningFlag
- 比较
bytes
要么bytearray
与str
要么bytes
用int
。如果大于等于2
.由设置
-b
选项。
Py_DebugFlag
- 打开解析器调试输出(仅限专家,取决于编译选项).
由
-d
选项和PYTHONDEBUG
环境变量设置
Py_DontWriteBytecodeFlag
- 如果设置为非零,Python将不会尝试写入
.pyc
源模块的进口文件.由设置
-B
选项和PYTHONDONTWRITEBYTECODE
环境变量
Py_FrozenFlag
- 在
Py_GetPath()
.中计算模块搜索路径时,取消错误信息
_freeze_importlib
和frozenmain
程序设置的私有标志
Py_HashRandomizationFlag
- 设置为
1
如果PYTHONHASHSEED
环境变量设置为非空字符串.如果标志非零,请阅读
PYTHONHASHSEED
environmentvariable初始化秘密哈希种子.
Py_IgnoreEnvironmentFlag
- 忽略所有
PYTHON*
环境变量,例如PYTHONPATH
和PYTHONHOME
,可以设置设置
-E
和-I
选项
Py_InspectFlag
- 当脚本作为第一个参数或
-c
使用选项,执行脚本或命令后进入交互模式,即使在sys.stdin
似乎不是一个终端.由设置
-i
选项和PYTHONINSPECT
environmentvariable.
Py_InteractiveFlag
- 由设置
-i
选项。
Py_IsolatedFlag
- 以隔离模式运行Python。在隔离模式下
sys.path
包含脚本的目录和用户的site-packages目录.由设置
-I
选项。版本3.4.
Py_LegacyWindowsFSEncodingFlag
- 中的新功能如果标志非零,请使用
mbcs
编码而不是UTF-8编码进行文件系统编码.设置为
1
如果PYTHONLEGACYWINDOWSFSENCODING
environmentvariable设置为非空字符串.参见 PEP 529 了解更多详情.
可用性:Windows.
Py_LegacyWindowsStdioFlag
- 如果标志非零,请使用
io.FileIO
代替WindowsConsoleIO
sys
标准流.设置为
1
如果PYTHONLEGACYWINDOWSSTDIO
环境变量设置为非空字符串参见 PEP 528了解更多详情.
可用性:Windows.
Py_NoSiteFlag
- 禁用导入模块
site
以及它所需的sys.path
的站点相关操作。如果稍后显式导入site
,也要禁用这些操作(调用site.main()
如果你想让它们被触发).设置
-S
选项.
Py_NoUserSiteDirectory
- 不要把
user site-packages directory
添加到sys.path
.由
-s
和-I
选项设置,和PYTHONNOUSERSITE
环境变量
Py_OptimizeFlag
- 设置
-O
选项和PYTHONOPTIMIZE
environmentvariable.
Py_QuietFlag
- 即使在交互模式下也不要显示版权和版本信息.
由设置
-q
选项。版本3.2.
Py_UnbufferedStdioFlag
- 强制stdout和stderr流无缓冲.
设置
-u
选项和PYTHONUNBUFFERED
环境变量.
Py_VerboseFlag
- 每次初始化模块时都打印一条消息,显示加载模块的位置(文件名或内置模块)。如果大于或等于
2
,为搜索模块时检查的每个文件打印一条消息。还提供退出时模块清理的信息.由设置
-v
选项和PYTHONVERBOSE
environmentvariable.
初始化和完成翻译
- void
Py_Initialize
() -
初始化Python解释器。在嵌入Python的应用程序中,应该在使用任何其他Python / C API函数之前调用它;看看在Python初始化之前少数例外.
初始化加载模块表(
sys.modules
),并创建基本模块builtins
,__main__
和sys
。它还初始化模块搜索路径(sys.path
)。它没有设置sys.argv
;使用PySys_SetArgvEx()
。这是第二次调用时的无操作(没有先调用Py_FinalizeEx()
)。没有回报价值;如果初始化失败则是afatal错误.注意
在Windows上,将控制台模式从
O_TEXT
更改为O_BINARY
,这将影响使用C Runtime的控制台的非Python用法.
- void
Py_InitializeEx
( int initsigs) - 如果
Py_Initialize()
是initsigs,这个功能就像1
一样。如果initsigs是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解释器的应用程序可能希望释放Python卸载DLL之前分配的所有内存。在寻找内存泄漏的过程中,应用程序开发人员可能希望在退出应用程序之前释放Python分配的所有内存.
Bugs and caveats:模块中模块和对象的销毁完成随机顺序;这可能会导致析构函数(
__del__()
方法)当它们依赖于其他对象(甚至函数)或模块时失败。不会卸载由Python加载的动态加载的扩展模块。Python解释器分配的少量内存可能无法释放(如果发现泄漏,请报告)。在对象之间的循环引用中绑定的内存是不可能的。扩展模块分配的某些内存可能无法释放。如果初始化例程被调用超过一次,则某些扩展可能无法正常工作;如果应用程序调用Py_Initialize()
和Py_FinalizeEx()
不止一次.新版本3.6.
- void
Py_Finalize
() - 是
Py_FinalizeEx()
的向后兼容版本,它忽略了返回值.
过程参数
- int
Py_SetStandardStreamEncoding
( const char *encoding,const char *errors) -
这个函数应该在
Py_Initialize()
,如果它被调用的话。它指定了与标准IO一起使用的编码和错误处理,其含义与str.encode()
.它会覆盖
PYTHONIOENCODING
值,并允许嵌入代码来控制IO编码当环境变量不起作用时encoding
和/或errors
可能为NULL使用PYTHONIOENCODING
和/或默认值(取决于在otherettings).请注意
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_*
string.
- wchar*
Py_GetProgramName
() -
返回用
Py_SetProgramName()
设置的程序名,或默认值。返回的字符串指向静态存储;调用者不应修改其值.
- wchar_t*
Py_GetPrefix
() - 返回prefix以获取已安装的与平台无关的文件。这是通过使用
Py_SetProgramName()
设置的程序名和一些环境变量的许多复杂规则得出的;例如,如果程序名称为"/usr/local/bin/python"
,则前缀为"/usr/local"
。将字符串指向静态存储;调用者不应修改其值。这对应于顶层中的前缀Makefile
变量和--prefix
配置的参数脚本在构建时。该值可用于Python代码sys.prefix
它只对Unix有用。另见下一个功能.
- wchar_t*
Py_GetExecPrefix
() - 返回exec-prefix安装平台 – dependent文件。这是通过使用
Py_SetProgramName()
设置的程序名和一些环境变量的许多复杂规则得出的;例如,如果程序名称为"/usr/local/bin/python"
,则exec-prefix为"/usr/local"
。返回的字符串指向静态存储;调用者不应修改其值。这对应于顶层和中的Makefile
exec_prefix--exec-prefix
在构建时配置脚本的参数。该值可以作为sys.exec_prefix
用于Python代码。它只适用于Unix.背景:当平台依赖文件(例如可执行文件和共享库)安装在不同的目录树中时,exec-prefix与前缀不同。在典型安装中,平台相关文件可能安装在
/usr/local/plat
独立于平台的子树可能安装在/usr/local
.一般而言,平台是硬件和软件系列的组合,例如,运行Solaris 2.x操作系统的Sparc机器被认为是同一平台,但运行Solaris 2.x的英特尔机器是另一个平台,运行Linux的英特尔机器是另一个平台。同一操作系统的不同主要修订版通常也形成不同的平台。非Unix操作系统是一个不同的故事;这些系统上的安装策略是如此不同,前缀和exec前缀是无意义的,并设置为空字符串。请注意,编译的Python字节码文件是独立于平台的(但不是独立于编译它们的Python版本!)。
系统管理员将知道如何配置 mount 或 automount 程序到分享
/usr/local
平台之间有/usr/local/plat
是每个平台的不同文件系统
- wchar_t *
Py_GetProgramFullPath
() -
返回Python可执行文件的完整程序名称;这被计算为从程序名称(由上面的
Py_SetProgramName()
设置)导出默认模块搜索路径的旁效。返回的字符串指向内部存储;调用者不应修改其值。该值可用于//代码sys.executable
.
- wchar_t *
Py_GetPath
() -
返回默认模块搜索路径;这是根据程序名称(由上面的
Py_SetProgramName()
设置)和一些环境变量计算出来的。返回的字符串由一系列由平台依赖的分隔符分隔的目录名组成。在Unix和Mac OS X上,分隔符是":"
,在Windows上是";"
。返回的字符串指向内部存储;调用者不应修改其值。列表sys.path
在解释器启动时使用此值初始化;它可以(并且通常是)稍后修改以更改loadingmodules的搜索路径.
- void
Py_SetPath
( const wchar_t *) -
设置默认模块搜索路径。如果在
Py_Initialize()
之前调用此函数,则Py_GetPath()
将不会尝试计算默认搜索路径,而是使用提供的搜索路径。如果Python完全了解所有模块的位置,那么这很有用。路径组件应该由平台相关的分隔符分隔,在Unix和Mac OS X上是":"
,在Windows上";"
这也导致
sys.executable
仅设置为原始程序名(请参阅Py_SetProgramName()
),并且sys.prefix
和sys.exec_prefix
为空。在调用Py_Initialize()
.后使用
Py_DecodeLocale()
解码一个字节字符串来获取wchar_*
string.路径参数在内部复制,因此调用者可以在调用完成后释放它.
- const char *
Py_GetVersion
() - 返回此Python解释器的版本。这是一个看起来像
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
第一个单词(直到第一个空格字符)是当前的Python版本;前三个字符是由aperiod分隔的主要和次要版本。返回的字符串指向静态存储;调用者不应该修改它的值。该值可用于//代码
sys.version
.
- const char *
Py_GetPlatform
() -
返回当前平台的平台标识符。在Unix上,这是从操作系统的“官方”名称,转换为小写,然后是主要修订号;例如,对于Solaris 2.x,也称为SunOS 5.x,值为
"sunos5"
。在Mac OS X上,它是"darwin"
。在Windows上,它是"win"
。返回的字符串指向内部存储;调用者不应修改其值。该值可用于//代码sys.platform
.
- const char *
Py_GetCopyright
() - 返回当前Python版本的官方版权字符串,例如
"Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam"
返回的字符串指向静态存储;调用者不应修改其值。该值可用于//代码
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中的第一个条目可以是一个emptystring。如果此函数无法初始化sys.argv
,则使用Py_FatalError()
.发出致命信号。如果updatepath为零,则这是函数的全部功能。如果updatepath非零,则该函数还会根据以下算法修改
sys.path
:- 如果现有脚本的名称在
argv[0]
中传递,脚本所在目录的绝对路径前置于sys.path
. - 否则(即,如果argc是
0
或argv[0]
不指向现有的文件名),一个空字符串被添加到sys.path
,这与前面的当前工作目录("."
).
使用
Py_DecodeLocale()
相同解码字节字符串得wchar_*
字符串注意事项
建议将Python解释器嵌入到执行单个脚本以外的目的的应用程序将
0
传递给updatepath,并在需要时自行更新sys.path
。参见CVE-2008-5983。在3.1.3之前的版本中,你可以通过在调用
sys.path
之后手动删除第一个PySys_SetArgv()
元素来达到相同的效果,例如使用:PyRun_SimpleString("import sys; sys.path.pop(0)\n");
版本3.1.3.
- 如果现有脚本的名称在
- void
PySys_SetArgv
( int argc,wchar_t **argv) - 函数就像
PySys_SetArgvEx()
和updatepath setto1
一样,除非 python 解释器是用-I
.启动的
Py_DecodeLocale()
解码字节字符串以获得wchar_*
字符串更改版本3.4: updatepath值取决于
-I
.
- void
Py_SetPythonHome
( const wchar_t *home) - 设置默认的“home”目录,即standardPython的位置库。请参阅
PYTHONHOME
了解theargument string的含义.参数应指向staticstorage中以零结尾的字符串,其内容在程序执行期间不会更改。Python解释器中没有代码会改变这个存储的内容.
使用
Py_DecodeLocale()
解码字节字符串得到wchar_*
字符串
- //w_char*
Py_GetPythonHome
() - 返回默认的“home”,即前一次调用
Py_SetPythonHome()
设置的值,或者PYTHONHOME
环境变量如果设置的话
Thread State和Global Interpreter Lock
Python解释器不是完全线程安全的。为了支持多线程Python程序,有一个全局锁,叫 globalinterpreter 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
宏打开一个新块并声明了一个ahidden局部变量;Py_END_ALLOW_THREADS
宏关闭theblock.
上面的块扩展为以下代码:
PyThreadState *_save;
_save = PyEval_SaveThread();
... Do some blocking I/O operation ...
PyEval_RestoreThread(_save);
以下是这些函数的工作方式:全局解释器锁用于保护指针当前的线程状态。释放锁并保存线程状态时,必须在释放锁之前检索当前线程状态指针(因为另一个线程可以立即获取锁并将其自己的线程状态存储在全局变量中)。相反,在获取锁定并恢复线程状态时,必须在存储线程状态指针之前获取锁定.
注意
调用系统I / O函数是释放GIL的最常见用例,但在调用不需要访问Python对象的长时间运行计算之前它也很有用,例如在内存缓冲区上运行的压缩或加密函数。例如,标准zlib
和hashlib
模块在压缩或散列数据时释放GIL .
Non-Python创建的线程
当使用专用线程创建线程时Python API(例如threading
模块),一个线程状态自动与上面显示的代码相关联,因此是正确的。但是,当从C创建线程时(例如,由具有自己的线程管理的第三方库),它们不持有GIL,也没有线程状态结构.
如果你需要从这些线程调用Python代码(通常这将是上述第三方库提供的回调API的一部分),你必须首先通过创建线程状态数据结构,然后获取GIL来向解释器注册这些线程,在开始使用Python / CAPI之前,最后存储它们的线程状态指针。完成后,你应该重置线程状态指针,释放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_*()
函数假设只有一个globalinterpreter(由Py_Initialize()
自动创建)。Pythons支持创建额外的解释器(使用Py_NewInterpreter()
),但混合多个解释器和PyGILState_*()
API不受支持
关于线程的另一个重要注意事项是它们在C fork()
调用中的行为。在大多数系统上fork()
,在进程分叉之后,只存在发出fork的线程。alsomeans其他线程持有的任何锁永远不会被释放。通过获取它在fork之前内部使用的锁,并在之后释放它们来解决os.fork()
的Python问题。另外,它会重置锁定物体在孩子身上。在扩展或嵌入Python时,没有办法告知Python需要在fork之前获取或在fork之后重置的其他(非Python)锁。需要使用pthread_atfork()
等操作系统来完成相同的操作。另外,在扩展或嵌入Python时,直接调用fork()
而不是通过os.fork()
(并返回到或者调用Python)可能会导致一个Python的内部锁定所造成的死锁,这个锁定是在fork.PyOS_AfterFork_Child()
尝试重置必要的锁之后解散的一个线程所持有的,但是总是无法解决.
高级API
这些是编写C扩展码或嵌入Python解释器时最常用的类型和函数:
PyInterpreterState
- 此数据结构表示由许多协作线程共享的状态。属于同一解释器的线程共享其模块管理和一些其他内部项。这个结构中没有公共成员.
属于不同解释器的线程最初没有任何共享,除了可用内存,打开文件描述符等进程状态。globalinterpreter lock也由所有线程共享,无论它们属于哪个解释器.
PyThreadState
- 这个数据结构代表单个线程的状态。唯一的publicdata成员是
PyInterpreterState *
interp
,它指向该线程的解释器状态.
- void
PyEval_InitThreads
() -
初始化并获取全球翻译锁。它应该在创建第二个线程之前在主线程中调用,或者参与任何其他线程操作,例如
PyEval_ReleaseThread(tstate)
。在调用之前不需要PyEval_SaveThread()
或PyEval_RestoreThread()
.这是第二次调用时的无操作.
在版本3.7中更改:此功能现在由
Py_Initialize()
调用,所以你不必打电话它自己了.在版本3.2:在
Py_Initialize()
anymore.
- int
PyEval_ThreadsInitialized
() - 如果
PyEval_InitThreads()
被称为。可以在不保持GIL的情况下调用此函数,因此可以在运行single -threaded时使用它来禁止对锁定API的调用.更改版本3.7:GIL 现在由
Py_Initialize()
.
- 初始化为PyThreadState *
PyEval_SaveThread
() - 释放全局解释器锁(如果已创建)和threadsupport已启用)并将线程状态重置为NULL,返回以前的线程状态(不是NULL)。如果已创建锁,则当前线程必须已获取它.
- void
PyEval_RestoreThread
( PyThreadState *tstate) - 获取全局解释器锁(如果已创建并启用了线程支持)并将线程状态设置为tstate,这不能是NULL。如果已经创建了锁,则当前线程一定不能获取它,否则会发生死锁.
- PyThreadState*
PyThreadState_Get
() - 返回当前线程状态。必须保持全局解释器锁。当前线程状态为NULL时,会发出致命错误(这样调用者无需检查NULL)。
- PyThreadState*
PyThreadState_Swap
( PyThreadState *tstate) - 用参数tstate给出的线程状态交换当前线程状态,这可能是是NULL。全局解释器锁必须保持并且不释放.
- void
PyEval_ReInitThreads
() - 这个函数从
PyOS_AfterFork_Child()
调用到确保新创建的子进程不保存指向未在子进程中运行的线程的锁.
以下函数使用线程本地存储,并且与子解释器不兼容:
- PyGILState_STATE
PyGILState_Ensure
() - 确保当前线程已准备好调用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处于相同的状态。虽然允许递归调用,但这些句柄cannot是共享的 – 每次调用PyGILState_Ensure()
必须保存其callto的句柄PyGILState_Release()
.当函数返回时,当前线程将保持GIL并且能够调用任意Python代码。失败是一个致命的错误.
- void
PyGILState_Release
( PyGILState_STATE ) - 释放以前获得的任何资源。在此调用之后,Python的状态将与相应的
PyGILState_Ensure()
调用之前的状态相同(但通常调用者将不知道此状态,因此使用了GILState API).每个调用
PyGILState_Ensure()
必须在同一个线程上调用PyGILState_Release()
来匹配
- PyThreadState*
PyGILState_GetThisThreadState
() - 获取此线程的当前线程状态。如果在当前线程上使用了noGILState API,则可以返回
NULL
。请注意,即使主线程上没有进行自动线程状态调用,主线程也具有这样的线程状态。这主要是辅助/诊断功能.
- 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
() - 创建一个新的解释器状态对象。不需要保持全局解释器锁,但是如果需要序列化对该函数的调用,则可以保持它.
- void
PyInterpreterState_Clear
( PyInterpreterState *interp) - 重置解释器状态对象中的所有信息。必须保持全局解释器.
- void
PyInterpreterState_Delete
( PyInterpreterState *interp) - 销毁解释器状态对象。不需要看全局解释器锁。解释器状态必须先重新调用
PyInterpreterState_Clear()
.
- PyThreadState *
PyThreadState_New
( PyInterpreterState *interp) - 创建一个新的属于给定解释器对象的线程状态对象。不需要保持全局解释器锁,但是如果必须序列化对此函数的调用,则可以保持它.
- void
PyThreadState_Clear
( PyThreadState *tstate) - 重置线程状态对象中的所有信息。全局解释器锁必须被保持.
- void
PyThreadState_Delete
( PyThreadState *tstate) - 销毁一个线程状态对象。不需要保存全局解释器锁。线程状态必须先前调用
PyThreadState_Clear()
.
- PY_INT64_T
PyInterpreterState_GetID
( PyInterpreterState *interp) - 返回解释器的唯一ID。如果在执行中有任何错误,则返回
-1
并设置错误.版本3.7.
- PyObject*
PyThreadState_GetDict
() - Return value: Borrowed reference.
返回一个字典,其中扩展可以存储特定于线程的状态信息。每个扩展都应使用唯一键来用于在字典中存储状态。当没有当前线程状态可用时,可以调用此函数。如果此函数返回NULL,则不会引发任何异常,并且调用者应假定当前没有可用的线程状态.
- int
PyThreadState_SetAsyncExc
( unsigned long id,PyObject *exc) - 在线程中异步引发异常。idargument是目标线程的threadid;exc是要引发的异常对象。这个函数不会窃取对exc的任何引用。为了防止天真滥用,你必须编写自己的C扩展来调用它。必须在保持GIL的情况下调用。返回已修改的线程状态数;这通常是一个,但如果找不到线程id,则为零。如果exc是
NULL
,则清除线程的pendingexception(如果有的话)。这没有例外.版本3.7: id参数的类型从
long
改为unsigned long
.
- void
PyEval_AcquireThread
( PyThreadState *tstate) - 获取全局解释器锁并将当前线程状态设置为tstate,这不应该是NULL。必须先创建锁。如果此线程已经锁定,则会发生死锁.
PyEval_RestoreThread()
是一个更高级别的函数,它始终可用(即使线程尚未初始化).
- void
PyEval_ReleaseThread
( PyThreadState *tstate) - 将当前线程状态重置为NULL并释放全局解释器锁。锁必须先创建,并且必须由currentthread保存。tstate参数,不能是NULL,仅用于检查它是否代表当前线程状态 – 如果不是,则报告致命错误.
PyEval_SaveThread()
是一个总是可用的高级函数(即使线程尚未初始化).
- void
PyEval_AcquireLock
() - 获取全局解释器锁。必须先创建锁。如果此线程已经锁定,则会出现死锁.
自版本3.2:后重新编写此函数不会更新当前线程状态。请使用
PyEval_RestoreThread()
或PyEval_AcquireThread()
instead.
- void
PyEval_ReleaseLock
() - 释放全局解释器锁。锁必须是先前创建的.
自版本3.2:后重新编写此函数不会更新当前的线程状态。请使用
PyEval_SaveThread()
或PyEval_ReleaseThread()
instead.
子解释支持
虽然在大多数用途中,您只会嵌入一个Python解释器,但在这种情况下,您需要在同一进程中创建几个独立的解释器,甚至可能在同一个线程中。副译员允许你这样做。您可以使用PyThreadState_Swap()
功能在子解释器之间切换。您可以使用以下函数创建和销毁它们:
- PyThreadState *
Py_NewInterpreter
() -
创建一个新的子解释器。这是一个(几乎)完全独立的环境,用于执行Python代码。特别是,新的解释器具有所有导入模块的独立版本,包括基本模块
builtins
,__main__
和sys
。加载模块的表(sys.modules
)和模块搜索路径(sys.path
)也是分开的。新环境没有sys.argv
变量。它有新的标准I / O流文件对象sys.stdin
,sys.stdout
和sys.stderr
(但是它们指的是相同的底层文件描述符).返回值指向在newsub-interpreter中创建的第一个线程状态。此线程状态在当前线程状态下进行。注意没有创建实际线程;请参阅线程状态的讨论。如果新解释器的创建不成功,则返回NULL;由于异常状态存储在当前线程状态并且可能没有当前线程状态,因此未设置异常。(与所有其他Python / C API函数一样,全局解释器锁必须在调用此函数之前保持,并且在返回时仍然保持;但是,与其他大多数Python / C API函数不同,不需要当前的线程状态onentry。)
扩展模块在(子)解释器之间共享如下:第一次导入特定扩展,正常初始化,并且其模块字典的(浅)副本被squirreled。当另一个(子)解释器导入相同的扩展时,初始化一个新模块并填充该副本的内容;扩展名的
init
函数未被调用。请注意,这与通过调用Py_FinalizeEx()
和Py_Initialize()
完全重新初始化解释器后导入扩展名时的情况不同。在这种情况下,扩展名的initmodule
功能is再次调用.
- void
Py_EndInterpreter
( PyThreadState *tstate) -
销毁由给定线程状态表示的(子)解释器。giventhread状态必须是当前线程状态。请参阅下面的threadstates讨论。当调用返回时,当前线程状态为NULL。与此解释器关联的Allthread状态将被销毁。(必须在调用此函数之前保持globalinterpreter锁定,并且在返回时仍然保持。)
Py_FinalizeEx()
将销毁那时尚未明确销毁的所有子解释器.
Bugs and caveats
因为子解释器(和主解释器)是同一个进程的一部分,它们之间的绝缘并不完美 – 例如,使用像os.close()
他们可以(意外或恶意)影响彼此的打开文件。由于(子)解释器之间共享扩展,一些扩展可能无法正常工作;当扩展使用(静态)全局变量时,或者扩展在初始化后操作其模块的字典时,这种情况尤其可能发生。可以将在一个子解释器中创建的对象插入到另一个子解释器的命名空间中;这应该非常小心,以避免在子解释器之间共享用户定义的函数,方法,实例或类,因为这些对象执行的导入操作可能会影响错误的(子)解释器的loadedmodules字典。
另请注意,将此功能与PyGILState_*()
APIsis很精细,因为这些API假定Python线程状态和操作系统级线程之间存在双射,这是由子解释器的存在所打破的假设。强烈建议您不要在一对匹配之间切换子解释器PyGILState_Ensure()
和PyGILState_Release()
调用。此外,使用这些API以允许从非Python创建的线程调用Python代码的扩展(例如ctypes
)在使用子解释器时可能会被破坏.
异步通知
提供了一种机制来向主解释器线程发出异步通知。这些通知采用functionpointer和void指针参数的形式.
- int
Py_AddPendingCall
(int(*func)(void *),void *arg) -
安排从主解释器线程调用的函数。Onsuccess,
0
返回func排队等待在主线程中调用。失败时,-1
返回时没有设置任何异常.成功排队后,func将是eventually使用参数arg从主解释器线程调用。对于正常运行的Python代码,它将被异步调用,但满足这两个条件:
- 在字节码边界;
- 主线程持有全局解释器锁(func因此可以使用完整的C API).
func必须在成功时返回
0
,或-1
因异常而失败。func不会被中断以递归方式执行另一个异步通知,但如果释放全局解释器锁,它仍然可以被中断到switchthreads .这个函数不需要运行当前的线程状态,也不需要全局解释器锁.
Warning
这是一个低级功能,仅适用于非常特殊的情况。不能保证func会尽可能快地调用。如果主线程忙于执行系统调用,func在系统调用返回之前不会被调用。这个函数一般不适合调用Python代码fromarbitrary C线程。相反,使用 PyGILState API .
版本3.1.
分析和追踪
Python解释器为附加分析和执行跟踪工具提供了一些低级支持。这些用于分析,调试和覆盖分析工具.
此C接口允许分析或跟踪代码,以避免通过Python级可调用对象进行调用的开销,从而使得直接C函数调用。该设施的基本属性没有改变;接口允许每个线程安装跟踪功能,并且报告给跟踪功能的基本事件与以前版本中报告给Python级别跟踪功能的基本事件相同.
- int
(*Py_tracefunc)
( PyObject *obj,PyFrameObject *frame,int what,PyObject *arg) - 使用
PyEval_SetProfile()
和PyEval_SetTrace()
。第一个参数是传递给注册函数的对象obj, frame是事件所在的框架对象,what是常量之一PyTrace_CALL
,PyTrace_EXCEPTION
,PyTrace_LINE
,PyTrace_RETURN
,PyTrace_C_CALL
,PyTrace_C_EXCEPTION
,PyTrace_C_RETURN
或PyTrace_OPCODE
,和arg取决于what:的价值 what 的意思 arg PyTrace_CALL
总是 Py_None
.PyTrace_EXCEPTION
返回的异常信息 sys.exc_info()
.PyTrace_LINE
总是 Py_None
.PyTrace_RETURN
值返回给调用者,或NULL如果由异常引起的. PyTrace_C_CALL
被调用的函数对象. PyTrace_C_EXCEPTION
被调用的函数对象. PyTrace_C_RETURN
被调用的函数对象. PyTrace_OPCODE
总是 Py_None
.
- int
PyTrace_CALL
- 的价值what参数到
Py_tracefunc
当报告函数或方法的newcall或生成器的新条目时函数。注意,没有报告为生成器函数创建迭代器,因为没有控制转移到相应框架中的Python字节码。
- int
PyTrace_EXCEPTION
- 当引发异常时,what参数的值为
Py_tracefunc
函数。使用what在处理任何字节码之后,在正在执行的帧内设置异常。这样做的结果是,由于异常传播导致Python堆栈展开,因此当异常传播时,回调被调用到每个帧。只有跟踪功能才能接收这些事件;分析器不需要它们
- //
PyTrace_LINE
- 当what参数传递给
Py_tracefunc
函数(但不是分析函数)的值时正在报告行号事件。可以通过在该帧上设置f_trace_lines
到0来禁用帧.
- int
PyTrace_RETURN
- 值对于what参数到
Py_tracefunc
当acall即将返回时的函数.
- int
PyTrace_C_CALL
- what参数的值为
Py_tracefunc
即将调用Cfunction时的函数
- //
PyTrace_C_EXCEPTION
- //功能时what参数的值
Py_tracefunc
起作用已经引发异常.
- int
PyTrace_C_RETURN
- 当一个Cfunction返回时,what参数的值为
Py_tracefunc
的功能.
- //
PyTrace_OPCODE
- 的值调用回调函数what当一个新的操作码即将被执行时,
Py_tracefunc
函数的参数(但不是配置函数)。默认情况下不会发出此事件:必须通过将f_trace_opcodes
设置为1在框架上
- void
PyEval_SetProfile
( Py_tracefunc func,PyObject *obj) - 设置探查器功能至 func。obj参数作为第一个参数传递给函数,可以是任何Python对象,或NULL。如果配置文件功能需要维护状态,请使用不同的值obj为每个线程提供了一个方便且线程安全的存储位置。除了
PyTrace_LINE
PyTrace_OPCODE
和PyTrace_EXCEPTION
.
- 无效
PyEval_SetTrace
(Py_tracefunc func,PyObject *obj) - 将跟踪功能设置为func。这类似于
PyEval_SetProfile()
,除了跟踪函数确实接收line-numberevents和per-opcode事件,但是没有收到与被调用的C函数对象相关的任何事件。使用PyEval_SetTrace()
注册的任何跟踪功能都不会接收PyTrace_C_CALL
,PyTrace_C_EXCEPTION
或PyTrace_C_RETURN
作为what参数的值
Advanced Debugger Support
这些函数仅供高级调试工具使用.
- PyInterpreterState *
PyInterpreterState_Head
() - 返回解释器状态对象在所有这些对象的列表的头部.
- PyInterpreterState*
PyInterpreterState_Next
( PyInterpreterState *interp) - 返回下一个从所有对象的列表interp之后解释状态对象.
- PyThreadState *
PyInterpreterState_ThreadHead
( PyInterpreterState *interp) - 将指针返回到与解释器关联的线程列表中的第一个
PyThreadState
对象interp.
- PyThreadState *
PyThreadState_Next
( PyThreadState *tstate) - 从属于同一个tstate的所有这些对象的列表中返回
PyInterpreterState
object
//本地存储支持
Python解释器为线程本地存储(TLS)提供低级支持,它包装底层本机TLS实现以支持Python级线程本地存储API(threading.local
)。CPython C级API类似于pthreads和Windows提供的API:使用线程键和函数关联void*
值perthread.
GIL确实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 )
Py_tss_t
- 此数据结构表示线程键的状态,其定义为可能依赖于底层的TLS实现,它有一个表示密钥初始化状态的内部字段。在这个结构中有nopublic成员.
当 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
初始化,则行为未定义。这个函数可以在同一个键上重复调用 – 在已经初始化的键上调用它是ano-op并立即返回成功.
- void
PyThread_tss_delete
( Py_tss_t *key) - 销毁TSS密钥以忘记跨所有线程的密钥关联值,并将密钥的初始化状态更改为未初始化。Adestroyed键可以通过
PyThread_tss_create()
再次初始化。这个函数可以在同一个键上重复调用 – 在已经被破坏的键上调用它是一个no-op.
- int
PyThread_tss_set
( Py_tss_t *key,void *value) - 返回一个零值,表示
void*
值与当前线程中的TSS键成功关联。每个线程都有一个独特的键映射到void*
值.
- void *
PyThread_tss_get
( Py_tss_t *key) - 返回
void*
与当前线程中的TSS密钥关联的值。这返回NULL如果没有值与当前线程中的键相关联
线程本地存储(TLS)API
从版本3.7开始不推荐使用:该API被取代线程特定存储(TSS)API .
注意
此版本的API不支持以无法安全地转换为int
的方式定义本机TLS键的平台。在这样的平台上,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
()