threading — 基于线程的并行

源代码: Lib/threading.py


此模块构造更高级线程接口,基于更低级 _thread 模块。

3.7 版改变: 此模块曾经是可选的,现在始终可用。

另请参阅

concurrent.futures.ThreadPoolExecutor 提供更高级接口以将任务压入后台线程,不阻塞调用线程的执行,同时仍然能在需要时检索他们的结果。

queue 为在运行线程之间交换数据,提供线程安全接口。

asyncio 提供达成任务级并发的替代方式,不要求使用多个操作系统线程。

注意

在 Python 2.x 系列,此模块包含 camelCase 名称对于某些方法和函数。这些从 Python 3.10 起弃用,但仍支持它们为兼容 Python 2.5 及以下版本。

CPython 实现细节: 在 CPython,由于 全局解释器锁 ,一次仅一线程可以执行 Python 代码 (即使某些面向性能的库可以克服此局限性)。若想让应用程序更好地利用多核机器的计算资源,建议使用 multiprocessing or concurrent.futures.ProcessPoolExecutor 。不管怎样,threading 仍是合适模型若想要同时运行多个 I/O 绑定任务。

可用性 :非 Emscripten,非 WASI。

本模块不工作 (或不可用) 于 WebAssembly 平台 wasm32-emscripten and wasm32-wasi 。见 WebAssembly 平台 了解更多信息。

此模块定义了下列函数:

threading. active_count ( )

返回数量为 Thread 对象的目前存活。返回计数等于列表长度,列表返回通过 enumerate() .

函数 activeCount 是此函数的弃用别名。

threading. current_thread ( )

返回当前 Thread 对象,对应调用者控制线程。若调用者控制线程的创建不是透过 threading 模块,返回具有有限功能的虚设线程对象。

函数 currentThread 是此函数的弃用别名。

threading. excepthook ( args , / )

处理未捕获异常引发通过 Thread.run() .

args 自变量拥有下列属性:

  • exc_type :异常类型。

  • exc_value :异常值,可以是 None .

  • exc_traceback :异常回溯,可以是 None .

  • thread :引发异常的线程,可以是 None .

exc_type is SystemExit ,异常被默默忽略。否则,异常被打印输出到 sys.stderr .

若此函数引发异常, sys.excepthook() 被调用以处理它。

threading.excepthook() 可以被覆盖以控制如何未捕获异常引发通过 Thread.run() 被处理。

存储 exc_value 使用自定义挂钩可以创建引用循环。应明确清零以中断引用循环,当不再需要异常时。

存储 thread 使用自定义挂钩可以复活它,若它被设为正定稿对象。避免存储 thread 在自定义挂钩完成后以避免复活对象。

另请参阅

sys.excepthook() 处理未捕获异常。

3.8 版新增。

threading. __excepthook__

保持原始值为 threading.excepthook() 。保存它以便还原原始值,若它们被损坏 (或替代) 对象所替换。

3.10 版新增。

threading. get_ident ( )

返回当前线程的 "线程标识符"。这是非 0 整数。它的值没有直接意义;旨在作为魔法 Cookie 使用 (如:索引特定线程数据的字典)。线程标识符会被回收,当退出线程并创建另一线程时。

3.3 版新增。

threading. get_native_id ( )

返回由内核赋值的当前线程的本机整形线程 ID。这是非负整数。可以使用它的值唯一标识系统范围内的此特定线程 (直到线程终止,之后 OS 会回收该值)。

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

3.8 版新增。

threading. enumerate ( )

返回列表为所有 Thread 对象 (目前活动)。列表包括守护线程和虚设线程对象创建通过 current_thread() 。不包括已终止线程和尚未启动的线程。不管怎样,主线程始终是结果的一部分,甚至在终止时。

threading. main_thread ( )

返回主 Thread 对象。在正常情况下,主线程是启动 Python 解释器的哪个线程。

3.4 版新增。

threading. settrace ( func )

为所有线程设置跟踪函数开始于 threading 模块。 func 将被传递给 sys.settrace() 为各线程,先于其 run() 方法被调用。

threading. gettrace ( )

获取跟踪函数如设置通过 settrace() .

3.10 版新增。

threading. setprofile ( func )

为所有线程设置 profile 函数开始于 threading 模块。 func 将被传递给 sys.setprofile() 为各线程,先于其 run() 方法被调用。

threading. getprofile ( )

获取剖分析器函数如设置通过 setprofile() .

3.10 版新增。

threading. stack_size ( [ size ] )

返回创建新线程时使用的线程堆栈大小。可选 size 自变量指定用于随后创建线程的堆栈大小,且必须为 0 (使用平台或配置默认的) 或至少 32,768 (32 KB) 的正整数值。若 size 未指定,使用 0。若不支持改变线程堆栈大小, RuntimeError 被引发。若指定堆栈大小无效, ValueError 被引发且未修改堆栈大小。32 KB 是目前支持的最小堆栈大小值,以保证解释器本身堆栈空间足够。注意,某些平台可能对堆栈大小值有特定限制,譬如要求最小堆栈大小 > 32KB 或要求按系统内存页面大小的倍数分配 - 要了解更多信息请参考平台文档编制 (4KB 页面很常见;建议堆栈大小使用 4096 的倍数方式,当缺乏更具体信息时)。

可用性 :Windows、PThreads。

支持 POSIX 线程的 Unix 平台。

此模块还定义了下列常量:

threading. TIMEOUT_MAX

最大允许值为 timeout 参数对于阻塞函数 ( Lock.acquire() , RLock.acquire() , Condition.wait() ,等)。指定大于此值的超时将引发 OverflowError .

3.2 版新增。

此模块定义了许多类,以下章节会详细描述。

此模块的设计基于 Java 的松散线程化模型。然而,Java 使锁和条件变量成为每个对象的基本行为,它们在 Python 中是独立对象。Python 的 Thread 类是支持 Java 线程类行为的子集;目前,没有优先级,没有线程组,线程无法被销毁、停止、挂起、恢复或中断。Java 线程类的静态方法,在实现时被映射到了模块级函数。

下文描述的所有方法都以原子方式执行。

线程局部数据

线程局部数据是值为特定线程的数据。要管理线程局部数据,仅仅创建实例化的 local (或子类) 并在其中存储属性:

mydata = threading.local()
mydata.x = 1
						

实例的值异于单独线程。

class threading. local

表示线程局部数据的类。

对于更多细节和广泛范例,见文档编制字符串在 _threading_local 模块。

线程对象

Thread 类表示在单独控制线程中运行的活动。有 2 种方式指定活动:通过将可调用对象传递给构造函数,或通过覆盖 run() 方法在子类中。不应覆盖子类中的其它方法 (除构造函数外)。换句话说, only 覆写 __init__() and run() 方法对于此类。

线程对象一旦被创建,它的活动就必须被启动通过调用线程的 start() 方法。这援引 run() 方法在单独控制线程中。

一旦线程活动开始,就认为线程 "存活"。它将停止存活当其 run() 方法被终止 – 正常或通过引发未处理异常。 is_alive() 方法测试线程是否存活。

其它线程可以调用线程的 join() 方法。这阻塞调用线程,直到线程的 join() 方法被调用才终止。

线程有名称。名称会被传递给构造函数,且读取和改变是透过 name 属性。

run() 方法引发异常, threading.excepthook() 被调用以处理它。默认情况下, threading.excepthook() 默默忽略 SystemExit .

可以将线程标志为 "守护线程"。此标志的意义,整个 Python 程序退出当只剩守护线程时。初始值继承自创建线程。标志可以设置透过 daemon 特性或 daemon 构造函数自变量。

注意

守护线程在关闭时会突然停止。它们的资源 (譬如:打开文件、数据库事务、等) 不可能正确释放。若想要线程优雅停止,使它们成为非守护并使用合适的发信号机制,譬如 Event .

存在 "主线程" 对象;这相当于 Python 程序中的初始控制线程。它不是守护线程。

有可能创建 "虚设线程对象"。这些是 "外来线程" 的对应线程对象,是在 threading 模块外开始的控制线程 (譬如:直接从 C 代码)。虚设线程对象拥有有限功能;认为它们始终存活和守护,且不可以 joined 。它们从不被删除,由于不可能检测外来线程的终止。

class threading. Thread ( group = None , target = None , name = None , args = () , kwargs = {} , * , daemon = None )

始终应采用关键词自变量调用此构造函数。自变量:

group 应该为 None ;预留以供未来扩展当 ThreadGroup 类被实现。

target 是要被援引的可调用对象通过 run() 方法。默认为 None ,意味着什么都不调用。

name 是线程名称。默认情况下,唯一名称构造形式为 Thread- N 其中 N 是 小十进制数字,或 Thread- N (target) 其中 target 是 target.__name__ target 自变量有指定。

args 是用于援引目标的自变量列表 (或元组)。默认为 () .

kwargs 是援引目标的关键词自变量字典。默认为 {} .

若非 None , daemon 明确设置线程是否为守护线程。若 None (默认),守护特性继承自当前线程。

若子类覆盖构造函数,它必须确保援引基类构造函数 ( Thread.__init__() ) 在对其它线程做任何事情之前。

3.10 版改变: 使用 target 名称若 name 自变量被省略。

3.3 版改变: 添加 daemon 自变量。

start ( )

启动线程活动。

每个线程对象必须最多调用它一次。它安排对象的 run() 方法以在单独控制线程中被援引。

此方法将引发 RuntimeError 若在同一线程对象中多次调用。

run ( )

表示线程活动的方法。

可以在子类中覆盖此方法。标准 run() 方法援引传递给对象构造函数的可调用对象作为 target 自变量,若有的话,采用的位置和关键字自变量获取自 args and kwargs 自变量,分别。

使用列表 (或元组) 作为 args 自变量传递给 Thread 可以达成相同效果。

范例:

>>> from threading import Thread
>>> t = Thread(target=print, args=[1])
>>> t.run()
1
>>> t = Thread(target=print, args=(1,))
>>> t.run()
1
						
join ( timeout = None )

等待直到线程终止。这阻塞调用线程,直到线程的 join() 方法被调用才终止 – 正常或透过未处理异常 – 或直到发生可选超时。

timeout 自变量存在且非 None ,它应该是以秒 (或其分数) 为单位指定操作超时的浮点数。由于 join() 始终返回 None ,必须调用 is_alive() after join() 决定是否发生超时 – 若线程仍存活, join() 调用将超时。

timeout 自变量不存在或 None ,操作将阻塞,直到线程终止。

线程可以毗连多次。

join() 引发 RuntimeError 若试图 join 当前线程,因为这会导致死锁。它也会出错当 join() 线程,在线程开始前试图这样做会引发相同异常。

name

仅用于标识用途的字符串。它没有语义。可以赋予多个线程相同名称。初始名称由构造函数设置。

getName ( )
setName ( )

弃用 getter/setter API 对于 name ;直接将其用作代替特性。

从 3.10 版起弃用。

ident

此线程的 "线程标识符" 或 None 若线程尚未开始。这是非 0 整数。见 get_ident() 函数。线程标识符会被回收,当线程退出并创建另一线程时。标识符可用,即使在线程已退出后。

native_id

线程 ID ( TID ) 对于此线程,由 OS (内核) 赋值。这是非负整数,或 None 若线程尚未开始。见 get_native_id() 函数。此值可以用作此特定线程系统范围的唯一标识 (直到线程终止,之后值可能被 OS 回收)。

注意

类似 PID (进程 ID),TID (线程 ID) 在线程被创建时才有效 (保证系统范围唯一),直到线程终止。

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

3.8 版新增。

is_alive ( )

返回线程是否存活。

此方法返回 True 恰好先于 run() 方法开始直到恰好后于 run() 方法终止。模块函数 enumerate() 返回所有存活线程的列表。

daemon

布尔值指示此线程是否为守护线程 ( True ) 或不 ( False )。必须设置这先于 start() 被调用,否则 RuntimeError 被引发。其初始值继承自创建线程;主线程不是守护线程,因此,在主线程中创建的所有线程默认为 daemon = False .

整个 Python 程序退出,当未剩下存活的非守护线程时。

isDaemon ( )
setDaemon ( )

弃用 getter/setter API 对于 daemon ;直接将其用作代替特性。

从 3.10 版起弃用。

锁对象

原语锁是锁定时不属于特定线程的同步原语。在 Python 中,它目前是可用的最低级同步原语,直接实现通过 _thread 扩展模块。

原语锁处于锁定或解锁 2 种状态之一。它是在解锁状态下创建的。它拥有 2 个基本方法, acquire() and release() 。当在解锁状态时, acquire() 将状态改为锁定并立即返回。当在锁定状态时, acquire() 阻塞直到调用 release() 在另一线程中将其改为解锁,然后 acquire() 调用将它重置为锁定并返回。 release() 方法只应在锁定状态下调用;它将状态改为解锁并立即返回。若试图释放未锁定的锁, RuntimeError 会被引发。

锁还支持 上下文管理协议 .

当多个阻塞线程在 acquire() 等待状态变为解锁,仅一线程继续进行当 release() 调用将状态重置为解锁;哪个等待线程继续执行未定义,且可能因实现而异。

所有方法以原子方式执行。

class threading. Lock

实现原语锁对象的类。一旦线程有获得锁,会阻塞后续获得尝试,直到它被释放;任何线程都可以释放它。

注意, Lock 实际是返回平台支持具体 Lock 类的最有效版本实例的工厂函数。

acquire ( blocking = True , timeout = - 1 )

获得锁,阻塞或非阻塞。

当援引采用 blocking 自变量设为 True (默认),阻塞直到锁被解锁,然后将其设为锁定并返回 True .

当援引采用 blocking 自变量设为 False ,不阻塞。若调用采用 blocking 设为 True 将阻塞,返回 False 立即;否则,将锁设为锁定并返回 True .

当被援引采用浮点 timeout 自变量 (设为正值),最多阻塞秒数的指定通过 timeout 且只要无法获得锁。 timeout 自变量 -1 指定无限等待。禁止指定 timeout blocking is False .

返回值为 True 若成功获取锁, False 若不 (例如若 timeout 过期)。

3.2 版改变: timeout 参数是新增的。

3.2 版改变: 通过 POSIX 信号现在可以中断锁的获取,若底层线程实现支持它。

release ( )

释放锁。可以从任何线程调用这,不仅仅是已获得锁的线程。

当锁被锁定时,将其重置为解锁并返回。若任何其它线程被阻塞等待锁变为解锁,则准确允许某一线程继续进行。

当在解锁锁援引时, RuntimeError 被引发。

没有返回值。

locked ( )

返回 True 若获得锁。

RLock 对象

可重入锁是可以被同一线程多次获得的同步原语。在内部,它使用 owning thread (拥有线程) 和 recursion level (递归级别) 概念,除原语锁使用的锁定/解锁状态外。在锁定状态下,某个线程拥有锁;在解锁状态下,没有线程拥有它。

为锁定锁,线程调用它的 acquire() 方法;这返回,一旦线程拥有锁。为解锁锁,线程调用它的 release() 方法。 acquire() / release() 调用对可以嵌套;才最后 release() ( release() 最外侧对) 将锁重置为解锁,并允许阻塞另一线程当 acquire() 以继续进行。

可重入锁还支持 上下文管理协议 .

class threading. RLock

此类实现可重入锁对象。可重入锁必须由获得它的线程释放。一旦线程获得可重入锁,同一线程可以再次获得它不阻塞;线程必须释放它一次,每次获得它时。

注意, RLock 实际是工厂函数,返回由平台支持的具体 RLock 类的最高效版本实例。

acquire ( blocking = True , timeout = - 1 )

获得锁,阻塞或非阻塞。

当援引不带自变量:若此线程已经拥有锁,递归级别递增 1,并立即返回。否则,若另一线程拥有锁,阻塞直到锁被解锁。一旦锁被解锁 (不被任何线程拥有),则抓取所有权,将递归级别设为 1 并返回。若有多个线程被阻塞在等待直到锁被解锁,每次仅一个能抓取锁的所有权。在这种情况下,没有返回值。

当援引采用 blocking 自变量设为 True ,做相同事情如调用不带自变量,并返回 True .

当援引采用 blocking 自变量设为 False ,不阻塞。若调用不带自变量会阻塞,返回 False 立即;否则,做相同事情如调用不带自变量,并返回 True .

当被援引采用浮点 timeout 自变量 (设为正值),最多阻塞秒数的指定通过 timeout 且只要无法获得锁。返回 True 若已获得锁, False 若超时已过。

3.2 版改变: timeout 参数是新增的。

release ( )

释放锁,递减递归级别。若递减后为 0,将锁重置为解锁 (不被任何线程拥有),若任何其它线程被阻塞在等待锁变为解锁,仅允许它们之一继续。若递减后递归级别仍然非 0,锁依然锁定并由调用线程拥有。

才调用此方法,当调用线程拥有锁时。 RuntimeError 被引发若解锁锁时调用此方法。

没有返回值。

条件对象

条件变量始终关联某种锁;这可以传入 (或默认创建) 一个。传入一个很有用,当几个条件变量必须共享同一锁时。锁属于条件对象:不必单独追踪它。

条件变量遵从 上下文管理协议 :使用 with 语句可在封闭块持续时间内获得关联锁。 acquire() and release() 方法还调用关联锁的相应方法。

必须在持有关联锁时,调用其它方法。 wait() 方法释放锁,然后阻塞,直到另一个线程唤醒它通过调用 notify() or notify_all() 。一旦被唤醒, wait() 重新获得锁并返回。此外,还可以指定超时。

notify() 方法唤醒在等待条件变量的某一线程,若有在等待。 notify_all() 方法唤醒在等待条件变量的所有线程。

注意: notify() and notify_all() 方法不会释放锁;这意味着线程 (或被唤醒线程) 将不会返回从其 wait() 调用立即,但仅当线程调用 notify() or notify_all() 最后会放弃锁的所有权。

使用条件变量的典型编程样式,是使用锁同步访问某些共享状态;对特定状态变化感兴趣的线程会调用 wait() 重复直到它们看到期望状态,而修改状态的线程会调用 notify() or notify_all() 当它们改变状态时,以这种方式,它可能是某个等待者所期望的状态。例如,以下代码是具有不受限制缓冲容量的一般生产者/消费者情况:

# Consume one item
with cv:
    while not an_item_is_available():
        cv.wait()
    get_an_available_item()
# Produce one item
with cv:
    make_an_item_available()
    cv.notify()
					

while 循环校验应用程序条件是必要的,因为 wait() 可以在任意长时间后返回,且条件提示 notify() 调用可以不再保持 True。这是多线程编程所固有的。 wait_for() 方法可以用于自动条件校验,并简化计算超时:

# Consume an item
with cv:
    cv.wait_for(an_item_is_available)
    get_an_available_item()
					

要选取介于 notify() and notify_all() ,考虑一种状态的改变是否只对一个或多个正等待线程感兴趣。如:在典型生产者/消费者情况下,向缓冲添加一项只需唤醒一个消费者线程。

class threading. Condition ( lock = None )

此类实现条件变量对象。条件变量允许一个或多个线程去等待,直到由另一线程通知它们。

lock 自变量有给定且不是 None ,它必须是 Lock or RLock 对象,且它被用作底层锁。否则,新的 RLock 对象被创建并用作底层锁。

3.3 版改变: 从工厂函数变为类。

acquire ( * args )

获得底层锁。此方法调用底层锁对应方法;返回值是由相应方法返回的任何值。

release ( )

释放底层锁。此方法调用底层锁对应方法;没有返回值。

wait ( timeout = None )

等待直到被通知 (或直到发生超时)。若调用此方法时调用线程尚未获得锁, RuntimeError 被引发。

此方法释放底层锁,然后阻塞直到被唤醒由 notify() or notify_all() 调用对于在另一线程中的的相同条件变量,或直到发生可选超时为止。一旦被唤醒或超时,它重新获得锁并返回。

timeout 自变量存在且非 None ,它应该是以秒 (或其分数) 为单位指定操作超时的浮点数。

当底层锁为 RLock ,它不会被释放使用 release() 方法,由于这可能实际并未被解锁,当多次递归获得锁时。相反,内部接口的 RLock 类的使用,这真的会解锁,甚至在已递归获得几次时。然后使用另一内部接口恢复递归级别,当重新获得锁时。

返回值为 True 除非给定 timeout 过期,在这种情况下为 False .

3.2 版改变: 以前,方法总是返回 None .

wait_for ( predicate , timeout = None )

等待直到条件被评估为 True 止。 predicate 应该是其结果将被解释成布尔值的可调用。 timeout 可以提供最大给定等待时间。

此实用方法可以调用 wait() 重复直到 predicate (谓词) 被满足,或直到发生 timeout (超时)。返回值是谓词的最后返回值,并将评估为 False 若方法超时。

忽略超时特征,调用此方法大致相当于编写:

while not predicate():
    cv.wait()
			

因此,相同规则也适用于 wait() :调用时必须持有锁,而返回时重新获得锁。predicate (谓词) 在持有锁时评估。

3.2 版新增。

notify ( n = 1 )

默认情况下,只唤醒等待此条件的线程 (若有的话)。若调用线程未获得锁当调用此方法时, RuntimeError 被引发。

此方法最多唤醒 n 个等待条件变量的线程;无操作若没有线程在等待。

当前实现准确唤醒 n 线程,若至少 n 线程在等待。不管怎样,依赖此行为不安全。未来,优化实现可能偶尔唤醒超过 n 线程。

注意: 被唤醒线程并不实际返回从其 wait() 调用直到它可以重新获得锁。由于 notify() 不释放锁,其调用者应释放锁。

notify_all ( )

唤醒在等待此条件的所有线程。此方法的举动像 notify() , 但唤醒所有在等待线程,而不是一个。若调用线程未获得锁当调用此方法时, RuntimeError 被引发。

方法 notifyAll 是此方法的弃用别名。

信号量对象

这是计算机科学史中最古老的同步原语之一,由早期荷兰计算机科学家 Edsger W. Dijkstra 发明(他使用名称 P() and V() 而不是 acquire() and release() ).

信号量管理的内部计数器的递减是通过每 acquire() 调用和递增是通过每 release() 调用。计数器可以从不低于 0;当 acquire() 发现它为 0,阻塞,等待直到某些其它线程调用 release() .

信号量还支持 上下文管理协议 .

class threading. 信号量 ( value = 1 )

此类实现信号量对象。信号量管理的原子计数器表示数 release() 调用减数 acquire() 调用,加初始值。 acquire() 方法阻塞若有必要直到它可以在不用使计数器为负的情况下返回。若不给定, value 默认为 1。

可选自变量给出初始 value 对于内部计数器;默认为 1 。若 value 给定小于 0, ValueError 被引发。

3.3 版改变: 从工厂函数变为类。

acquire ( blocking = True , timeout = None )

获得信号量。

在没有自变量的情况下援引时:

  • 若内部计数器 > 0 在进入时,递减 1 并返回 True 立即。

  • 若内部计数器为 0 在进入时,阻塞,直到被唤醒通过调用 release() 。一旦被唤醒 (且计数器大于 0),计数器递减 1 并返回 True 。正好一线程被唤醒通过每次调用 release() 。唤醒不应该依赖线程的次序。

当被援引采用 blocking 设为 False ,不阻塞。若调用不带自变量会阻塞,返回 False 立即;否则,做相同事情如调用不带自变量,并返回 True .

当援引采用 timeout 除了 None ,它将阻塞最多 timeout 秒。若在该间隔内未成功完成获得,返回 False 。返回 True 否则。

3.2 版改变: timeout 参数是新增的。

release ( n = 1 )

释放信号量,将内部计数器递增 n 。当它为 0 在进入时,且其它线程在等待它再次大于 0 时,唤醒 n 线程对于这些。

3.9 版改变: 添加 n 参数以一次释放多个等待线程。

class threading. BoundedSemaphore ( value = 1 )

实现有界信号量对象的类。有界信号量会校验,以确保其当前值不超过其初始值。若履行, ValueError 被引发。在大多数情况下,信号量用于守卫容量有限的资源。若释放信号量太多次,有 Bug 迹象。若不给定, value 默认为 1。

3.3 版改变: 从工厂函数变为类。

Semaphore 范例

信号量经常用于守卫容量有限的资源 (例如:数据库服务器)。在资源大小固定的任何情况下,都应使用有界信号量。在卵生任何工作者线程前,主线程会初始化信号量:

maxconnections = 5
# ...
pool_sema = BoundedSemaphore(value=maxconnections)
	

一旦卵生,工作者线程会调用信号量的获得和释放方法,当它们需要连接到服务器时:

with pool_sema:
    conn = connectdb()
    try:
        # ... use connection ...
    finally:
        conn.close()
	

使用有界信号量可以减少编程出错的机会,但会导致要多要释放的信号量,而不是获得检测。

事件对象

这是线程之间的最简单通信机制之一:一个线程发出事件信号,而其它线程等待它。

事件对象管理可以设为 True 的内部标志采用 set() 方法和重置为 False 采用 clear() 方法。 wait() 方法阻塞直到标志为 True。

class threading. Event

实现事件对象的类。可以将事件管理标志设为 True 采用 set() 方法和重置为 False 采用 clear() 方法。 wait() 方法阻塞,直到标志为 True。标志最初为 False。

3.3 版改变: 从工厂函数变为类。

is_set ( )

返回 True 当且仅当内部标志为 True 时。

方法 isSet 是此方法的弃用别名。

set ( )

将内部标志设为 True。在等待它的所有线程变为 True,被唤醒。线程调用 wait() 一旦标志为 True 将根本不阻塞。

clear ( )

将内部标志重置为 False。随后,线程调用 wait() 将阻塞直到 set() 被调用,再次将内部标志设为 True。

wait ( timeout = None )

阻塞,直到内部标志为 True。若进入时内部标志为 True,立即返回。否则,阻塞直到另一线程调用 set() 将标志设为 True,或直到发生可选 timeout (超时)。

当 timeout 自变量存在且非 None ,它应该是以秒 (或其分数) 为单位指定操作超时的浮点数。

此方法返回 True 当且仅当内部标志被设为 True 时,在等待调用之前或在等待开始之后,所以它总是返回 True 除了有给定 timeout (超时),且操作超时。

3.1 版改变: 以前,方法总是返回 None .

计时器对象

此类表示仅在经过一定数量时间后才应运行的动作 — 计时器。 Timer 是子类化的 Thread 因此,也可以作为创建自定义线程的范例。

就像线程,计时器的启动是通过调用它们的 start() 方法。计时器的停止 (在它的动作开始之前) 是通过调用 cancel() 方法。计时器在执行它的动作之前的等待间隔,与由用户指定的间隔可能不会准确相同。

例如:

def hello():
    print("hello, world")
t = Timer(30.0, hello)
t.start()  # after 30 seconds, "hello, world" will be printed
class threading. Timer ( interval , function , args = None , kwargs = None )

创建计时器将运行 function 采用自变量 args 和关键词自变量 kwargs ,后于 interval 秒过去。若 args is None (默认) 那么将使用空列表。若 kwargs is None (默认) 那么将使用空字典。

3.3 版改变: 从工厂函数变为类。

cancel ( )

停止计时器,并取消计时器动作的执行。这才工作,若计时器仍处于等待阶段。

屏障对象

3.2 版新增。

此类提供简单同步原语,供需要相互等待的固定数量线程使用。每个线程会试着穿过屏障通过调用 wait() 方法并阻塞直到所有线程完成它们的 wait() 调用。此时,线程被同时释放。

可以重用屏障任意多次,对于相同数量的线程而言。

例如,这里是客户端和服务器线程的简单同步方式:

b = Barrier(2, timeout=5)
def server():
    start_server()
    b.wait()
    while True:
        connection = accept_connection()
        process_server_connection(connection)
def client():
    b.wait()
    while True:
        connection = make_connection()
        process_client_connection(connection)
class threading. 屏障 ( parties , action = None , timeout = None )

创建屏障对象为 parties 数量的线程。 action ,当提供时,是释放线程时由它们中某一线程调用的可调用。 timeout 是默认超时值,若指定 None 为 wait() 方法。

wait ( timeout = None )

通过屏障。当屏障的所有线程都有调用此函数时,将同时释放它们。若 timeout 有提供,首选使用它,相比提供给类构造函数的任何。

返回值是整数在范围 0 到 parties – 1,每个线程都不同。这可以用于选择线程做一些特殊内务,如:

i = barrier.wait()
if i == 0:
    # Only one thread needs to print this
    print("passed the barrier")
	

action 有提供给构造函数,某一线程会先于释放调用它。若此调用引发错误,会把屏障置于中断状态。

若调用超时,会把屏障置于中断状态。

此方法可能引发 BrokenBarrierError 异常,若屏障被中断 (或重置) 当线程在等待时。

reset ( )

返回空状态默认屏障。在等待它的任何线程将收到 BrokenBarrierError 异常。

注意,使用此函数可能要求一些外部同步,若存在状态未知的其它线程。若屏障被中断,最好还是离开它并创建一个新的屏障。

abort ( )

把屏障置于中断状态。这会导致任何活动或未来调用 wait() 失败采用 BrokenBarrierError 。例如,若某个线程需要中止,使用这能避免应用程序死锁。

更可取的是只需创建屏障采用合理 timeout 值来自动守卫某一线程的出错。

parties

要求通过屏障的线程数。

n_waiting

目前在屏障中等待的线程数。

broken

布尔为 True 若屏障处于中断状态。

exception threading. BrokenBarrierError

此异常是子类化的 RuntimeError ,被引发当 Barrier 对象被重置或中断。

使用锁、条件和信号量在 with 语句

由此模块提供的所有对象拥有 acquire() and release() 方法可以用作上下文管理器对于 with 语句。 acquire() 方法将被调用当进入块时,和 release() 将被调用当退出块时。因此,以下片段:

with some_lock:
    # do something...

相当于:

some_lock.acquire()
try:
    # do something...
finally:
    some_lock.release()

目前, Lock , RLock , Condition , Semaphore ,和 BoundedSemaphore 对象可以用作 with 语句上下文管理器。