_thread — 低级线程 API


此模块提供了用于处理多线程(也称为轻量级进程任务)的低级原语,即多个控制线程共享其全局数据空间。 为了进行同步,提供了简单的锁(也称为互斥锁二进制信号量)。 threading 模块在此模块的基础上提供了一个更易于使用和更高级的线程 API。

版本 3.7 中的变化: 此模块以前是可选的,现在始终可用。

此模块定义了以下常量和函数

异常 _thread.error

在线程特定错误时引发。

版本 3.3 中的变化: 现在这是内置 RuntimeError 的同义词。

_thread.LockType

这是锁对象的类型。

_thread.start_new_thread(function, args[, kwargs])

启动一个新线程并返回其标识符。 该线程使用参数列表 *args*(必须是元组)执行函数 *function*。 可选的 *kwargs* 参数指定关键字参数的字典。

当函数返回时,线程将静默退出。

当函数因未处理的异常而终止时,将调用 sys.unraisablehook() 来处理该异常。 hook 参数的 *object* 属性是 *function*。 默认情况下,将打印堆栈跟踪,然后线程退出(但其他线程继续运行)。

当函数引发 SystemExit 异常时,将静默忽略它。

引发带有参数 functionargskwargs审计事件 _thread.start_new_thread

版本 3.8 中的变化: 现在使用 sys.unraisablehook() 来处理未处理的异常。

_thread.interrupt_main(signum=signal.SIGINT, /)

模拟主线程中到达信号的效果。 线程可以使用此函数来中断主线程,尽管不能保证中断会立即发生。

如果给出,*signum* 是要模拟的信号编号。 如果未给出 *signum*,则模拟 signal.SIGINT

如果 Python 未处理给定的信号(它被设置为 signal.SIG_DFLsignal.SIG_IGN),则此函数不执行任何操作。

版本 3.10 中的变化: 添加了 *signum* 参数以自定义信号编号。

注意

这不会发出相应的信号,而是安排对关联处理程序的调用(如果存在)。 如果你想真正发出信号,请使用 signal.raise_signal()

_thread.exit()

引发 SystemExit 异常。 如果未捕获,这将导致线程静默退出。

_thread.allocate_lock()

返回一个新的锁对象。 锁的方法如下所述。 锁最初处于解锁状态。

_thread.get_ident()

返回当前线程的“线程标识符”。 这是一个非零整数。 它的值没有直接含义; 它旨在作为魔术cookie,例如用于索引线程特定数据的字典。 当一个线程退出并创建另一个线程时,线程标识符可能会被回收。

_thread.get_native_id()

返回由内核分配的当前线程的本机整数线程 ID。 这是一个非负整数。 它的值可用于在系统范围内唯一标识此特定线程(直到线程终止,之后该值可能会被操作系统回收)。

可用性:Windows、FreeBSD、Linux、macOS、OpenBSD、NetBSD、AIX、DragonFlyBSD。

3.8 版新增。

_thread.stack_size([size])

返回创建新线程时使用的线程堆栈大小。可选的 *size* 参数指定随后创建的线程要使用的堆栈大小,并且必须为 0(使用平台或配置的默认值)或至少为 32,768(32 KiB)的正整数值。如果未指定 *size*,则使用 0。如果不支持更改线程堆栈大小,则会引发 RuntimeError。如果指定的堆栈大小无效,则会引发 ValueError,并且堆栈大小不会被修改。32 KiB 是当前支持的最小堆栈大小值,以保证解释器本身有足够的堆栈空间。请注意,某些平台可能对堆栈大小的值有特殊的限制,例如要求最小堆栈大小 > 32 KiB 或要求以系统内存页面大小的倍数进行分配 - 应参考平台文档以获取更多信息(4 KiB 页面很常见;在没有更具体信息的情况下,建议使用 4096 的倍数作为堆栈大小)。

可用性:Windows、pthreads。

支持 POSIX 线程的 Unix 平台。

_thread.TIMEOUT_MAX

Lock.acquire 的 *timeout* 参数允许的最大值。指定大于此值的超时将引发 OverflowError

3.2 版新增。

Lock 对象具有以下方法

lock.acquire(blocking=True, timeout=-1)

没有任何可选参数时,此方法将无条件地获取锁,如有必要,将一直等待,直到它被另一个线程释放(一次只有一个线程可以获取锁 - 这就是它们存在的原因)。

如果存在 *blocking* 参数,则操作取决于其值:如果为 false,则仅当可以立即获取锁而无需等待时才获取锁,而如果为 true,则如上所述无条件地获取锁。

如果存在浮点型 *timeout* 参数且为正数,则它指定返回之前的最长等待时间(以秒为单位)。负的 *timeout* 参数指定无限期等待。如果 *blocking* 为 false,则不能指定 *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 异常将在获取锁后发生。

  • 当主线程退出时,其他线程是否存活取决于系统定义。在大多数系统上,它们会在不执行 tryfinally 子句或执行对象析构函数的情况下被终止。

  • 当主线程退出时,它不会执行任何常规清理(但会遵守 tryfinally 子句),并且不会刷新标准 I/O 文件。