_thread
--- 底层多线程 API¶
该模块提供了操作多个线程(也被称为 轻量级进程 或 任务)的底层原语 —— 多个控制线程共享全局数据空间。为了处理同步问题,也提供了简单的锁机制(也称为 互斥锁 或 二进制信号)。threading
模块基于该模块提供了更易用的高级多线程 API。
在 3.7 版更改: 这个模块曾经是可选的,但现在总是可用的。
这个模块定义了以下常量和函数:
-
exception
_thread.
error
¶ 发生线程相关错误时抛出。
在 3.3 版更改: 现在是内建异常
RuntimeError
的别名。
-
_thread.
LockType
¶ 锁对象的类型。
-
_thread.
start_new_thread
(function, args[, kwargs])¶ 开启一个新线程并返回其标识。 线程执行函数 function 并附带参数列表 args (必须是元组)。 可选的 kwargs 参数指定一个关键字参数字典。
当函数返回时,线程会静默地退出。
当函数因某个未处理异常而终结时,
sys.unraisablehook()
会被调用以处理异常。 钩子参数的 object 属性为 function。 在默认情况下,会打印堆栈回溯然后该线程将退出(但其他线程会继续运行)。当函数引发
SystemExit
异常时,它会被静默地忽略。在 3.8 版更改: 现在会使用
sys.unraisablehook()
来处理未处理的异常。
-
_thread.
interrupt_main
()¶ 模拟一个
signal.SIGINT
信号到达主线程的效果。 线程可以使用这个函数来中断主线程。如果 Python 没有处理
signal.SIGINT
(将它设为signal.SIG_DFL
或signal.SIG_IGN
),此函数将不做任何事。
-
_thread.
exit
()¶ 抛出
SystemExit
异常。如果没有捕获的话,这个异常会使线程退出。
-
_thread.
allocate_lock
()¶ 返回一个新的锁对象。锁中的方法在后面描述。初始情况下锁处于解锁状态。
-
_thread.
get_ident
()¶ 返回当前线程的 “线程描述符”。它是一个非零的整型数。它的值没有什么含义,主要是作为 magic cookie 使用,比如作为含有线程相关数据的字典的索引。线程描述符可能会在线程退出,新线程创建时复用。
-
_thread.
get_native_id
()¶ 返回内核分配给当前线程的原生集成线程 ID。 这是一个非负整数。 它的值可被用来在整个系统中唯一地标识这个特定线程(直到线程终结,在那之后该值可能会被 OS 回收再利用)。
可用性: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX。
3.8 新版功能.
-
_thread.
stack_size
([size])¶ 返回新建线程是用的堆栈大小。可选参数 size 指定之后新建的线程的堆栈大小,而且一定要是0(根据平台或者默认配置)或者最小是32,768(32KiB)的一个正整数。如果*size*没有指定,默认是0。如果不支持改变线程堆栈大小,会抛出
RuntimeError
错误。如果指定的堆栈大小不合法,会抛出ValueError
错误并且不会修改堆栈大小。32KiB是当前最小的能保证解释器足够堆栈空间的堆栈大小。需要注意的是部分平台对于堆栈大小会有特定的限制,例如要求大于32KiB的堆栈大小或者需要根据系统内存页面的整数倍进行分配 - 应当查阅平台文档有关详细信息(4KiB页面比较普遍,在没有更具体信息的情况下,建议的方法是使用4096的倍数作为堆栈大小)可用性: Windows,具有 POSIX 线程的系统。
-
_thread.
TIMEOUT_MAX
¶ Lock.acquire()
方法中 timeout 参数允许的最大值。传入超过这个值的 timeout 会抛出OverflowError
异常。3.2 新版功能.
锁对象有以下方法:
-
lock.
acquire
(waitflag=1, timeout=-1)¶ 没有任何可选参数时,该方法无条件申请获得锁,有必要的话会等待其他线程释放锁(同时只有一个线程能获得锁 —— 这正是锁存在的原因)。
如果传入了整型参数 waitflag,具体的行为取决于传入的值:如果是 0 的话,只会在能够立刻获取到锁时才获取,不会等待,如果是非零的话,会像之前提到的一样,无条件获取锁。
如果传入正浮点数参数 timeout,相当于指定了返回之前等待得最大秒数。如果传入负的 timeout,相当于无限期等待。如果 waitflag 是 0 的话,不能指定 timeout。
如果成功获取到所会返回
True
,否则返回False
。在 3.2 版更改: timeout 形参是新增的。
在 3.2 版更改: 现在获取锁的操作可以被 POSIX 信号中断。
-
lock.
release
()¶ 释放锁。锁必须已经被获取过,但不一定是同一个线程获取的。
-
lock.
locked
()¶ 返回锁的状态:如果已被某个线程获取,返回
True
,否则返回False
。
除了这些方法之外,锁对象也可以通过 with
语句使用,例如:
import _thread
a_lock = _thread.allocate_lock()
with a_lock:
print("a_lock is locked while this executes")
注意事项:
线程与中断奇怪地交互:
KeyboardInterrupt
异常可能会被任意一个线程捕获。(如果signal
模块可用的话,中断总是会进入主线程。)调用
sys.exit()
或是抛出SystemExit
异常等效于调用_thread.exit()
。不可能中断锁的
acquire()
方法 ——KeyboardInterrupt
一场会在锁获取到之后发生。当主线程退出时,由系统决定其他线程是否存活。在大多数系统中,这些线程会直接被杀掉,不会执行
try
...finally
语句,也不会执行对象析构函数。当主线程退出时,不会进行正常的清理工作(除非使用了
try
...finally
语句),标准 I/O 文件也不会刷新。