17.1. threading
—基于线程的并行性¶
源代码: Lib/threading.py
此模块在较低级别 _thread
模块的顶部构建更高级别的线程接口。另见 queue
模块。
dummy_threading
模块用于因为 _thread
缺失而无法使用 threading
的情况。
注解
虽然下面没有列出它们,但是在Python 2.x系列中用于本模块中某些方法和函数的 camelCase
名称仍然受此模块支持。
该模块定义了以下功能:
-
threading.
active_count
()¶ 返回当前活动的
Thread
对象的数量。返回的计数等于enumerate()
返回的列表的长度。
-
threading.
current_thread
()¶ 返回当前
Thread
对象,对应于调用者的控制线程。如果调用者的控制线程不是通过threading
模块创建的,则返回具有有限功能的虚拟线程对象。
-
threading.
get_ident
()¶ 返回当前线程的’线程标识符’。这是一个非零整数。它的价值没有直接的意义;它旨在作为要使用的魔术cookie。索引线程特定数据的字典。当线程退出并创建另一个线程时,线程标识符可以被回收。
3.3 新版功能.
-
threading.
enumerate
()¶ 返回当前活动的所有
Thread
对象的列表。该列表包括守护线程,由current_thread()
创建的虚拟线程对象和主线程。它排除了尚未启动的已终止线程和线程。
-
threading.
settrace
(func)¶ 为从
threading
模块启动的所有线程设置跟踪功能。在调用run()
方法之前,func 将被传递给每个线程的sys.settrace()
。
-
threading.
setprofile
(func)¶ 为从
threading
模块启动的所有线程设置配置文件功能。在调用run()
方法之前,func 将被传递给每个线程的sys.setprofile()
。
-
threading.
stack_size
([size])¶ 返回创建新线程时使用的线程堆栈大小。可选的 size 参数指定用于随后创建的线程的堆栈大小,并且必须为0(使用平台或配置的默认值)或至少为32,768(32 KiB)的正整数值。如果未指定 size,则使用0。如果不支持更改线程堆栈大小,则会引发
RuntimeError
。如果指定的堆栈大小无效,则会引发ValueError
并且堆栈大小未修改。 32 KiB是当前支持的最小堆栈大小值,以保证解释器本身有足够的堆栈空间。请注意,一些平台可能对堆栈大小的值有特殊限制,例如要求最小堆栈大小> 32 KiB或需要分配系统内存页大小的倍数 - 有关更多信息,请参阅平台文档(4 KiB页是常见的;使用4096的倍数作为堆栈大小是在没有更具体信息的情况下的建议方法)。可用性:Windows,具有POSIX线程的系统。
该模块还定义了以下常量:
-
threading.
TIMEOUT_MAX
¶ 允许用于阻塞函数(
Lock.acquire()
,RLock.acquire()
,Condition.wait()
等)的 timeout 参数的最大值。指定超过此值的超时将产生OverflowError
。3.2 新版功能.
此模块定义了许多类,这些类在下面的章节中详细说明。
这个模块的设计是松散地基于Java的线程模型。但是,在Java使锁和条件变量每个对象的基本行为,它们在Python中是单独的对象。 Python的 Thread
类支持Java Thread类的行为的一个子集;当前,没有优先级,没有线程组,线程不能被销毁,停止,挂起,恢复或中断。 Java Thread类的静态方法在实现时被映射到模块级函数。
下面描述的所有方法都是原子执行的。
17.1.1. 线程本地数据¶
线程本地数据是其值是线程特定的数据。要管理线程本地数据,只需创建 local
(或子类)的实例并存储属性即可:
mydata = threading.local()
mydata.x = 1
实例的值对于不同的线程将是不同的。
-
class
threading.
local
¶ 代表线程本地数据的类。
有关更多详细信息和广泛的示例,请参阅
_threading_local
模块的文档字符串。
17.1.2. 线程对象¶
Thread
类表示在单独的控制线程中运行的活动。有两种方法来指定活动:通过将可调用对象传递给构造函数,或者通过重写子类中的 run()
方法。没有其他方法(除了构造函数)应该在子类中重写。换句话说,only 重写这个类的 __init__()
和 run()
方法。
创建线程对象后,必须通过调用线程的 start()
方法来启动其活动。这在单独的控制线程中调用 run()
方法。
一旦线程的活动开始,线程被认为是“活着的”。它在 run()
方法终止时停止运行 - 无论是正常终止,还是通过提高未处理的异常。 is_alive()
方法测试线程是否存活。
其他线程可以调用线程的 join()
方法。这将阻塞调用线程,直到终止调用 join()
方法的线程。
线程有一个名称。该名称可以传递给构造函数,并通过 name
属性读取或更改。
一个线程可以被标记为“守护线程”。这个标志的意义是,当只剩下守护线程时,整个Python程序退出。初始值从创建线程继承。该标志可以通过 daemon
属性或 daemon 构造函数参数设置。
注解
守护线程在关机时突然停止。他们的资源(例如打开的文件,数据库事务等)可能无法正确释放。如果你想让你的线程正常停止,使他们非守护进程,并使用一个合适的信号机制,如 Event
。
有一个“主线程”对象;这对应于Python程序中的初始控制线程。它不是守护线程。
存在创建“虚拟线程对象”的可能性。这些是与“外来线程”相对应的线程对象,其是在线程模块外部开始的控制线程,诸如直接从C代码。虚拟线程对象的功能有限;它们总是被认为是活的和守护的,并且不能被 join()
ed。它们从不被删除,因为不可能检测到外来线程的终止。
-
class
threading.
Thread
(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)¶ 此构造函数应始终使用关键字参数调用。参数是:
group 应为
None
;保留用于在实现ThreadGroup
类时的未来扩展。target 是要由
run()
方法调用的可调用对象。默认为None
,表示没有任何调用。name 是线程名称。默认情况下,唯一名称构造为“Thread-N ”形式,其中 N 是小十进制数。
args 是目标调用的参数元组。默认为
()
。kwargs 是目标调用的关键字参数的字典。默认为
{}
。如果不是
None
,daemon 显式设置线程是否为daemonic。如果是None
(默认值),daemonic属性从当前线程继承。如果子类覆盖了构造函数,它必须在对线程做任何其他事情之前调用基类构造函数(
Thread.__init__()
)。在 3.3 版更改: 添加了 daemon 参数。
-
start
()¶ 启动线程的活动。
每个线程对象最多必须调用一次。它安排对象的
run()
方法在单独的控制线程中被调用。如果在同一线程对象上多次调用
RuntimeError
,此方法将产生RuntimeError
。
-
run
()¶ 表示线程活动的方法。
您可以在子类中覆盖此方法。标准
run()
方法调用传递给对象的构造函数的可调用对象作为 target 参数,如果有的话,分别具有取自 args 和 kwargs 参数的顺序和关键字参数。
-
join
(timeout=None)¶ 等待,直到线程终止。这将阻塞调用线程,直到调用其
join()
方法的线程正常或通过未处理的异常终止,或直到可选超时发生。当 timeout 参数存在且不是
None
时,它应该是以秒(或其分数)指定操作超时的浮点数。由于join()
总是返回None
,您必须在join()
之后调用is_alive()
来决定是否发生超时 - 如果线程仍然活动,则join()
调用超时。当 timeout 参数不存在或
None
时,操作将阻塞,直到线程终止。一个线程可以被
join()
ed多次。如果尝试加入当前线程,则
join()
引发RuntimeError
,因为这将导致死锁。它也是一个错误,join()
一个线程之前,它已经开始,并尝试这样做引发相同的异常。
-
name
¶ 仅用于识别目的的字符串。它没有语义。多个线程可以给予相同的名称。初始名称由构造函数设置。
-
ident
¶ 该线程或
None
的“线程标识符”(如果线程尚未启动)。这是一个非零整数。参见_thread.get_ident()
功能。当线程退出并创建另一个线程时,线程标识符可以被回收。即使在线程退出后,标识符也可用。
-
is_alive
()¶ 返回线程是否存活。
此方法在
run()
方法开始之前返回True
,直到run()
方法终止之后。模块函数enumerate()
返回所有活动线程的列表。
-
daemon
¶ 一个布尔值,表示此线程是否为守护线程(True)或不是(False)。这必须在调用
start()
之前设置,否则会引发RuntimeError
。它的初始值从创建线程继承;主线程不是守护线程,因此在主线程中创建的所有线程默认为daemon
=False
。当没有活动非守护进程线程时,整个Python程序退出。
-
在CPython中,由于 Global Interpreter Lock,只有一个线程可以一次执行Python代码(即使某些性能导向的库可能克服这个限制)。如果希望应用程序更好地利用多核机器的计算资源,建议您使用 multiprocessing
或 concurrent.futures.ProcessPoolExecutor
。但是,如果要同时运行多个I/O绑定任务,线程仍然是一个合适的模型。
17.1.3. 锁定对象¶
原始锁是同步原语,在锁定时不属于特定线程。在Python中,它是当前可用的最低级同步原语,由 _thread
扩展模块直接实现。
原始锁处于两种状态“锁定”或“解锁”中的一种。它是在解锁状态下创建的。它有两个基本方法,acquire()
和 release()
。当状态解锁时,acquire()
将状态更改为锁定并立即返回。当状态被锁定时,acquire()
阻塞,直到对另一线程中的 release()
的调用将其改变为解锁,则 acquire()
调用将其重置为锁定并返回。 release()
方法应该只在锁定状态下调用;它将状态更改为已解锁并立即返回。如果试图释放解锁的锁,则会出现 RuntimeError
。
锁也支持 上下文管理协议。
当 acquire()
中有多个线程被阻塞等待状态转为解锁时,只有一个线程在 release()
调用将状态重置为未锁定时进行;等待线程中的哪一个进行未被定义,并且可以在实现之间变化。
所有方法都是原子执行的。
-
class
threading.
Lock
¶ 实现原语锁对象的类。一旦线程获得锁,随后的获取它的尝试阻塞,直到它被释放;任何线程都可以释放它。
在 3.3 版更改: 从工厂函数更改为类。
-
acquire
(blocking=True, timeout=-1)¶ 获取锁定,阻止或非阻止。
当 blocking 参数设置为
True
(默认值)时调用,阻塞直到锁被解锁,然后将其设置为锁定并返回True
。当使用设置为
False
的 blocking 参数调用时,不要阻止。如果 blocking 设置为True
的呼叫将阻塞,立即返回False
;否则,将锁设置为锁定并返回True
。当浮点 timeout 参数设置为正值时调用时,最多只能阻塞由 timeout 指定的秒数,并且只要不能获取锁定。
-1
的 timeout 参数指定无界等待。当 blocking 为假时,禁止指定 timeout。如果锁被成功获取,则返回值为
True
;如果不成功,则返回值为False
(例如,如果 timeout 已过期)。在 3.2 版更改: timeout 参数是新的。
在 3.2 版更改: 现在可以通过POSIX上的信号中断锁定获取。
-
release
()¶ 释放锁。这可以从任何线程调用,而不仅仅是已经获得锁的线程。
当锁被锁定时,将其重置为解锁,然后返回。如果任何其他线程被阻塞等待锁被解锁,则只允许其中一个线程继续。
当在解锁的锁上被调用时,
RuntimeError
被引发。没有返回值。
-
17.1.4. RLock对象¶
可重入锁是可以由同一线程多次获取的同步原语。在内部,除了由原语锁使用的锁定/解锁状态之外,它还使用“拥有线程”和“递归级别”的概念。在锁定状态下,一些线程拥有锁;在解锁状态下,没有线程拥有它。
要锁定锁,线程调用其 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
()¶ 释放锁,递减递归级别。如果在递减之后它为零,将锁重置为解锁(不由任何线程拥有),并且如果任何其他线程被阻塞等待锁被解锁,则允许其中一个继续。如果递减后递归级别仍然为非零,则锁保持锁定并由调用线程拥有。
只有当调用线程拥有锁时才调用此方法。如果在锁被解锁时调用此方法,则会引发
RuntimeError
。没有返回值。
-
17.1.5. 条件对象¶
条件变量总是与某种锁相关联;这可以传入或一个将默认创建。当几个条件变量必须共享同一个锁时,传递一个是有用的。锁定是条件对象的一部分:您不必单独跟踪它。
条件变量遵循 上下文管理协议:使用 with
语句在封闭块的持续时间内获取关联的锁。 acquire()
和 release()
方法也调用相关锁的相应方法。
其他方法必须调用相关锁持有。 wait()
方法释放锁,然后阻塞,直到另一个线程通过调用 notify()
或 notify_all()
唤醒它。一旦被唤醒,wait()
重新获取锁并返回。也可以指定超时。
notify()
方法唤醒等待条件变量的线程之一(如果有任何等待)。 notify_all()
方法唤醒所有等待条件变量的线程。
注意:notify()
和 notify_all()
方法不释放锁;这意味着被唤醒的线程或线程不会立即从它们的 wait()
调用返回,而是只有当调用 notify()
或 notify_all()
的线程最终放弃锁的所有权时。
使用条件变量的典型编程风格使用锁来同步对一些共享状态的访问;线程对状态调用 wait()
的特定改变感兴趣,直到它们看到期望的状态,而修改状态的线程在它们改变状态时调用 notify()
或 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()
调用的条件可能不再成立。这是多线程编程固有的。 wait_for()
方法可以用于自动化条件检查,并且减少超时的计算:
# Consume an item
with cv:
cv.wait_for(an_item_is_available)
get_an_available_item()
要在 notify()
和 notify_all()
之间进行选择,请考虑一个状态更改是否只对一个或多个等待线程感兴趣。例如。在典型的生产者 - 消费者情形中,向缓冲器添加一个项目仅需要唤醒一个消费者线程。
-
class
threading.
Condition
(lock=None)¶ 这个类实现条件变量对象。条件变量允许一个或多个线程等待,直到它们被另一个线程通知。
如果给出了 lock 参数而不是
None
,则它必须是Lock
或RLock
对象,并且它用作基础锁。否则,将创建一个新的RLock
对象并将其用作基础锁。在 3.3 版更改: 从工厂函数更改为类。
-
acquire
(*args)¶ 获取底层锁。这个方法调用底层锁的相应方法;返回值是该方法返回的任何值。
-
release
()¶ 释放底层锁。这个方法调用底层锁的相应方法;没有返回值。
-
wait
(timeout=None)¶ 等待直到通知或直到发生超时。如果调用该方法时调用线程没有获得锁,则会引发
RuntimeError
。此方法释放底层锁,然后阻塞,直到它被另一个线程中的相同条件变量的
notify()
或notify_all()
调用唤醒,或者直到可选超时发生。一旦被唤醒或超时,它重新获取锁并返回。当 timeout 参数存在且不是
None
时,它应该是以秒(或其分数)指定操作超时的浮点数。当底层锁是
RLock
时,它不是使用其release()
方法释放,因为这可能不会实际上解锁锁,当它被递归多次获取。相反,使用RLock
类的内部接口,即使它已被递归地多次获取,它也真的解锁它。然后,在重新获取锁时,使用另一个内部接口来恢复递归级别。返回值是
True
,除非给定的 timeout 过期,在这种情况下它是False
。在 3.2 版更改: 此前,该方法总是返回
None
。
-
wait_for
(predicate, timeout=None)¶ 等待条件的求值结果为true。 predicate 应该是一个可调用的结果将被解释为一个布尔值。可以提供 timeout 以给出最大等待时间。
此实用程序方法可以重复调用
wait()
,直到满足谓词,或直到超时发生。返回值是谓词的最后一个返回值,如果方法超时则将求值为False
。忽略超时功能,调用此方法大致相当于编写:
while not predicate(): cv.wait()
因此,与
wait()
相同的规则适用:锁必须在调用时保持,并在返回时重新获取。使用保持的锁来评估谓词。3.2 新版功能.
-
notify
(n=1)¶ 默认情况下,唤醒等待此条件的一个线程(如果有)。如果调用此方法时调用线程没有获取锁,则会引发
RuntimeError
。此方法最多唤醒等待条件变量的线程的 n;它是一个无操作,如果没有线程正在等待。
当前的实现精确地唤醒 n 线程,如果至少 n 线程正在等待。然而,依靠这种行为是不安全的。未来,优化的实现可能会偶尔唤醒超过 n 线程。
注意:唤醒的线程实际上不会从其
wait()
调用返回,直到它可以重新获取锁。由于notify()
不释放锁,其调用者应该。
-
notify_all
()¶ 唤醒所有等待此条件的线程。此方法类似于
notify()
,但唤醒所有等待的线程,而不是一个。如果调用该方法时调用线程没有获取锁,则会引发RuntimeError
。
-
17.1.6. 信号物体¶
这是计算机科学史上最古老的同步原语之一,由早期的荷兰计算机科学家Edsger W. Dijkstra发明(他使用名字 P()
和 V()
代替 acquire()
和 release()
)。
信号量管理内部计数器,该内部计数器由每个 acquire()
调用递减并且由每个 release()
调用递增。计数器永远不会低于零;当 acquire()
发现它为零时,它阻塞,等待一些其他线程调用 release()
。
Semaphores还支持 上下文管理协议。
-
class
threading.
Semaphore
(value=1)¶ 这个类实现了信号量对象。信号量管理表示
release()
呼叫的数量减去acquire()
呼叫的数量加上一个初始值的计数器。如果需要,acquire()
方法阻塞,直到它可以返回,而不使计数器为负。如果没有给出,value 默认为1。可选参数给出内部计数器的初始 value;它默认为
1
。如果给定的 value 小于0,则引发ValueError
。在 3.3 版更改: 从工厂函数更改为类。
-
acquire
(blocking=True, timeout=None)¶ 获取信号量。
当调用无参数时:如果内部计数器在入口时大于零,则将其减1并立即返回。如果它在入口为零,阻塞,等待,直到一些其他线程调用
release()
使其大于零。这是通过适当的互锁来完成的,因此如果多个acquire()
呼叫被阻塞,release()
将只唤醒其中一个。实现可以随机选择一个,因此不应依赖被阻塞的线程被唤醒的顺序。返回true(或无限块)。当使用 blocking 设置为false调用时,不要阻止。如果没有参数的调用将阻塞,立即返回false;否则,做与没有参数调用时相同的事情,并返回true。
当使用除
None
之外的 timeout 调用时,它将阻塞最多 timeout 秒。如果在该时间间隔内未成功完成捕获,则返回false。否则返回true。在 3.2 版更改: timeout 参数是新的。
-
release
()¶ 释放信号量,使内部计数器递增1。当它在条目上为零,并且另一个线程等待它再次变得大于零时,唤醒该线程。
-
-
class
threading.
BoundedSemaphore
(value=1)¶ 类实现有界信号对象。有界信号量检查以确保其当前值不超过其初始值。如果是,
ValueError
被提升。在大多数情况下,信号量用于保护有限容量的资源。如果信号量被释放太多次,这是一个错误的征兆。如果没有给出,value 默认为1。在 3.3 版更改: 从工厂函数更改为类。
17.1.6.1. Semaphore
示例¶
信号量通常用于保护有限容量的资源,例如数据库服务器。在任何情况下,资源的大小是固定的,你应该使用有界的信号量。在生成任何工作线程之前,你的主线程将初始化信号量:
maxconnections = 5
# ...
pool_sema = BoundedSemaphore(value=maxconnections)
一旦产生,工作线程在需要连接到服务器时调用信号量的获取和释放方法:
with pool_sema:
conn = connectdb()
try:
# ... use connection ...
finally:
conn.close()
有界信号量的使用减少了导致信号量被释放多于其获取的编程错误将不被检测的机会。
17.1.7. 事件对象¶
这是线程之间通信的最简单的机制之一:一个线程表示事件,而其他线程等待它。
事件对象管理内部标志,可以使用 set()
方法将其设置为true,并使用 clear()
方法将其复位为false。 wait()
方法阻塞,直到标志为真。
17.1.8. 计时器对象¶
这个类表示应该在一定时间过去之后才运行的动作 - 一个定时器。 Timer
是 Thread
的子类,因此也用作创建自定义线程的示例。
计时器被启动,如线程,通过调用他们的 start()
方法。定时器可以通过调用 cancel()
方法停止(在其动作开始之前)。定时器在执行其操作之前将等待的间隔可能与用户指定的间隔不完全相同。
例如:
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
17.1.9. 障碍对象¶
3.2 新版功能.
这个类提供了一个简单的同步原语,供需要彼此等待的固定数量的线程使用。每个线程尝试通过调用 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.
Barrier
(parties, action=None, timeout=None)¶ 为 parties 线程数创建一个屏障对象。 action (当提供时)是一个可调用的,当它们被释放时由其中一个线程调用。如果没有为
wait()
方法指定,timeout 是默认的超时值。-
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
¶ 当
Barrier
对象被复位或断开时,引发这个异常,即RuntimeError
的子类。
17.1.10. 在 with
语句中使用锁,条件和信号量¶
该模块提供的所有具有 acquire()
和 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
语句上下文管理器。