17.1. threading - 基于线程的并行性

源代码: Lib / threading.py

此模块在较低级别的_thread模块之上构建更高级别的线程接口。另请参见queue模块。

dummy_threading模块用于threading无法使用,因为_thread缺失的情况。

虽然下面没有列出,但是这个模块仍然支持Python 2.x系列中此模块中某些方法和函数使用的camelCase名称。

本模块定义了以下函数︰

threading.active_count()

返回当前处于alive状态的Thread对象的个数。返回的数目等于enumerate()返回的列表的长度。

threading.current_thread()

返回当前的Thread对象,对应于调用者控制的线程。如果调用者控制的线程不是通过threading模块创建的,则返回一个只有有限功能的虚假线程对象。

threading.get_ident()

返回当前线程的'线程标识符'。它是一个非零的整数。它的价值没有直接的意义;它旨在作为要使用的魔术cookie。索引线程特定数据的字典。当一个线程退出另外一个线程创建时,线程的ID可以重用。

版本3.3中的新功能。

threading.enumerate()

返回当前活着的Thread对象的列表。该列表包括守护线程、由current_thread()创建的虚假线程对象和主线程。它不包括已终止的线程和尚未开始的线程。

threading.main_thread()

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

版本3.4中的新功能。

threading.settrace(func)

为所有从threading模块启动的线程设置一个跟踪函数。在每个线程的run()方法调用之前,func将传递给sys.settrace()

threading.setprofile(func)

为所有从threading模块启动的线程设置一个profile函数。这个profile函数将在每个线程的run()方法被调用之前传递给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

这个 timeout参数表示阻塞函数 (Lock.acquire(), RLock.acquire(), Condition.wait(), 等)所允许等待的最长时限。指定超过此值的超时将引发OverflowError

版本3.2中的新功能。

下面的章节中详细说明了这个模块所定义的一系列类。

本模块的设计零散地基于Java的线程模型。然而,Java的锁和条件变量是每个对象的基本行为,在Python中它们是单独的对象。Python的Thread类支持Java Thread类的行为的一个子集;当前,没有优先级,没有线程组,线程不能被销毁,停止,挂起,恢复或中断。Java线程类的静态方法,如果实现,则映射成模块级别的函数。

下述所有方法的执行都是原子的。

17.1.1. Thread-Local Data

线程本地数据是其值是线程特定的数据。要管理thread-local数据,只需创建local(或其子类)的一个实例并在它上面存储属性:

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

该实例的值对于各自的线程将是不同的。

class threading.local

表示thread-local数据的一个类。

更多的细节和扩展示例,参见_threading_local模块的文档字符串。

17.1.2. Thread Objects

Thread类表示在单独的控制线程中运行的活动。有两种方式来指定活动︰ 通过将一个可调用对象传递到构造函数中,或通过在子类中的重写 run () 方法。没有其他方法(除了构造函数)应在子类中重写。换句话说,只可以 重写这个类的 __init__()run () 方法。

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

一旦线程活动启动,该线程被视为 '活着'。当其 run () 方法终止 — — 通常情况下,或raise未处理的异常时它不再是活着。is_alive() 方法测试线程是否还活着。

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

一个线程有一个名称。可以传递给构造函数,和读取或通过更改name 属性名称。

一个线程可以被标记为"daemon thread"。该标志的意思是整个Python程序在只剩下后台线程时才退出。它的初始值继承自创建它的线程。可以通过daemon属性或守护程序构造函数参数设置该标志。

守护线程在关机时被意外地终止。他们的资源(如打开文件,数据库事务等)可能无法正常释放。如果你想你的线程优雅地停止,可以把他们设置为为非守护的并使用一个合适的信号机制例如一个Event

有一个“主线程”对象;这对应于Python程序中的初始控制线程。它不是一个守护线程。

可能创建的是“虚拟的线程对象”。这些线程对象对应于“异质的线程”,它们是在threading模块之外启动的控制线程,例如直接从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守护程序显式设置线程是否为daemonic。如果None(默认值),daemonic属性从当前线程继承。

如果子类覆盖该构造函数,它必须保证在对线程做任何事之前调用基类的构造函数(Thread.__init__())。

在版本3.3中已更改:添加了守护程序参数。

start()

开始线程的活动。

每个线程对象必须只能调用它一次。它为对象的run()方法在一个单独的控制线程中调用做准备。

在相同的线程对象上调用该方法多次将引发一个RuntimeError

run()

表示线程活动的方法。

你可以在子类中覆盖这个方法。标准的run()方法调用传递给对象构造函数target参数的可调用对象,如果存在,分别从argskwargs参数获取顺序参数和关键字参数。

join(timeout=None)

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

timeout参数存在且不为None时,它应该以一个浮点数指定该操作的超时时间,单位为秒(可以是小数)。由于join()总是返回None,必须在调用is_alive()之后来join()决定是否发生超时 - 如果线程仍然存在,则join()调用超时。

如果timeout参数不存在或者为None,那么该操作将阻塞直至线程终止。

一个线程可以被join()多次。

如果尝试join当前的线程,join()会引发一个RuntimeError,因为这将导致一个死锁。它也是一个错误,join()一个线程之前,它已经开始,并尝试这样做引发相同的异常。

name

一个字符串,只用于标识的目的。它没有语义。多个线程可以被赋予相同的名字。初始的名字通过构造函数设置。

getName()
setName()

name;直接使用它作为属性。

ident

线程的ID,如果线程还未启动则为None它是一个非零的整数。请参见_thread.get_ident()函数。当一个线程退出另外一个线程创建时,线程的ID可以重用。即使在线程退出后,其ID仍然可以访问。

is_alive()

返回线程是否还活着。

run()方法刚开始之前至run()方法刚终止之后,该方法返回True模块级别的函数enumerate()返回所有活着的函数的一个列表。

daemon

布尔值,该值指示是否此线程一个守护进程线程 (True),或不 (False)。这必须调用start () 之前设置,否则 引发RuntimeError从创建的线程继承其初始的值,主线程不是守护线程,因此在主线程创建的所有线程的默认 daemon = False

整个的 Python 程序在没有活着的非守护程序线程运行时退出。

isDaemon()
setDaemon()

daemon的旧getter / setter API;直接使用它作为属性。

CPython实现细节:在CPython中,由于Global Interpreter Lock,只有一个线程可以一次执行Python代码(即使某些基于性能的库可能克服这个限制)。如果希望应用程序更好地利用多核机器的计算资源,建议使用multiprocessingconcurrent.futures.ProcessPoolExecutor然而,如果你想并发地运行多个I/O密集的任务,threading仍然是一个合适的模型。

17.1.3. Lock Objects

原锁是一个同步原语,当它锁住时不归某个特定的线程所有。在Python中,它是当前可用的最低级同步原语,由_thread扩展模块直接实现。

一个原锁处于“locked”或者“unlocked”状态中的一种。它创建时处于unlocked状态。它有两个基本方法,acquire()release()当状态是unlocked时,acquire()改变该状态为locked并立即返回。当状态被锁定时,acquire()阻塞,直到在另一个线程中对release()的调用将其改为unlocked,然后acquire()release()方法只应在锁定状态下调用;它将状态更改为已解锁并立即返回。如果尝试释放已解锁的锁,将会引发RuntimeError

锁定还支持context management protocol

acquire()中有多个线程被阻塞,等待状态变为未锁定时,只有一个线程在release()调用将状态重置为未锁定时进行;等待线程中的哪一个进行未被定义,并且可以在实现之间变化。

所有方法的执行都是原子的。

class threading.Lock

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

在版本3.3中更改:从工厂函数更改为类。

acquire(blocking=True, timeout=-1)

获取一把锁,阻塞的或者非阻塞的。

当调用时blocking参数设置为True(默认值),将阻塞直至锁变成unblocked,然后设置它的状态为locked并返回True

当调用时blocking参数设置为False,将不会阻塞。如果阻止设置为True的调用将被阻止,请立即返回False;否则,将锁定设置为锁定并返回True

当浮点超时参数设置为正值时调用时,最多只能阻塞timeout指定的秒数,只要无法获取锁定。-1timeout参数指定无界等待。阻止为false时,禁止指定超时

如果成功获取锁定,则返回值为True,如果未成功,则返回False(例如,如果超时过期)。

在版本3.2中更改: 超时参数是新的。

在版本3.2中更改:锁获取现在可以被POSIX上的信号中断。

release()

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

当锁是locked时,重置它为unlocked,然后返回。如果存在其他阻塞的线程正在等待锁变成unblocked状态,只会允许它们中的一个继续。

当在未锁定的锁上调用时,会引发RuntimeError

没有返回值。

17.1.4. RLock Objects

一个可重入所示一个同步原语,它可以被相同的线程获得多次。Internally, it uses the concepts of “owning thread” and “recursion level” in addition to the locked/unlocked state used by primitive locks. 在锁定状态下,一些线程拥有锁;在解锁状态下,没有线程拥有它。

要锁定锁,线程调用其acquire()方法;这个返回一旦线程拥有锁。To unlock the lock, a thread calls its release() method. acquire() / release()调用对可以嵌套;只有最后的release()(最外面的对的release())将锁重置为已解锁并允许另一个线程在acquire()

可重入锁还支持context management protocol

class threading.RLock

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

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

acquire(blocking=True, timeout=-1)

获取一把锁,阻塞的或者非阻塞的。

When invoked without arguments: if this thread already owns the lock, increment the recursion level by one, and return immediately. Otherwise, if another thread owns the lock, block until the lock is unlocked. Once the lock is unlocked (not owned by any thread), then grab ownership, set the recursion level to one, and return. If more than one thread is blocked waiting until the lock is unlocked, only one at a time will be able to grab ownership of the lock. There is no return value in this case.

When invoked with the blocking argument set to true, do the same thing as when called without arguments, and return true.

When invoked with the blocking argument set to false, do not block. 如果没有参数的调用将阻塞,立即返回false;否则,做与没有参数调用时相同的事情,并返回true。

当浮点超时参数设置为正值时调用时,最多只能阻塞timeout指定的秒数,只要无法获取锁定。如果已获取锁定,则返回true,如果超时已过,则返回false。

在版本3.2中更改: 超时参数是新的。

release()

Release a lock, decrementing the recursion level. If after the decrement it is zero, reset the lock to unlocked (not owned by any thread), and if any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed. If after the decrement the recursion level is still nonzero, the lock remains locked and owned by the calling thread.

Only call this method when the calling thread owns the lock. A RuntimeError is raised if this method is called when the lock is unlocked.

没有返回值。

17.1.5. Condition Objects

条件变量总是与某种锁相关联;这可以传入或一个将默认创建。当几个条件变量必须共享同一个锁时,传递一个是有用的。锁定是条件对象的一部分:您不必单独跟踪它。

条件变量遵守context management protocol:使用with语句在封闭块的持续时间内获取关联的锁。acquire()release()方法也调用相关锁的相应方法。

其他方法必须调用相关锁持有。wait()方法释放锁,然后阻塞,直到另一个线程通过调用notify()notify_all()唤醒它。一旦被唤醒,wait()重新获取锁并返回。It is also possible to specify a timeout.

The notify() method wakes up one of the threads waiting for the condition variable, if any are waiting. notify_all()方法唤醒所有等待条件变量的线程。

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

The typical programming style using condition variables uses the lock to synchronize access to some shared state; threads that are interested in a particular change of state call wait() repeatedly until they see the desired state, while threads that modify the state call notify() or notify_all() when they change the state in such a way that it could possibly be a desired state for one of the waiters. For example, the following code is a generic producer-consumer situation with unlimited buffer capacity:

# 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)

这个类实现条件变量对象。一个条件变量允许一个或多个线程等待直至它们收到另外一个线程的通知。

If the lock argument is given and not None, it must be a Lock or RLock object, and it is used as the underlying lock. Otherwise, a new RLock object is created and used as the underlying lock.

在版本3.3中更改:从工厂函数更改为类。

acquire(*args)

Acquire the underlying lock. 这个方法调用底层锁的相应方法;返回值是该方法返回的任何值。

release()

Release the underlying lock. 这个方法调用底层锁的相应方法;没有返回值。

wait(timeout=None)

Wait until notified or until a timeout occurs. If the calling thread has not acquired the lock when this method is called, a RuntimeError is raised.

这种方法释放底层锁,然后阻塞,直到它被一个notify()notify_all()唤醒,在另一个线程中调用相同的条件变量,或直到可选超时。Once awakened or timed out, it re-acquires the lock and returns.

When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).

When the underlying lock is an RLock, it is not released using its release() method, since this may not actually unlock the lock when it was acquired multiple times recursively. Instead, an internal interface of the RLock class is used, which really unlocks it even when it has been recursively acquired several times. Another internal interface is then used to restore the recursion level when the lock is reacquired.

除非给定的超时过期,此时返回值为True,在这种情况下为False

在版本3.2中更改:以前,该方法始终返回None

wait_for(predicate, timeout=None)

等待条件的计算结果为True。谓词应为可调用,其结果将被解释为布尔值。可以提供超时,给出最大等待时间。

此实用程序方法可重复调用wait(),直到满足谓词,或直到发生超时。返回值是谓词的最后一个返回值,如果方法超时,则计算为False

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

while not predicate():
    cv.wait()

Therefore, the same rules apply as with wait(): The lock must be held when called and is re-acquired on return. 谓词是保持锁的计算。

版本3.2中的新功能。

notify(n=1)

By default, wake up one thread waiting on this condition, if any. If the calling thread has not acquired the lock when this method is called, a RuntimeError is raised.

该方法最多唤醒等待条件变量的线程n;它是一个无操作,如果没有线程正在等待。

The current implementation wakes up exactly n threads, if at least n threads are waiting. However, it’s not safe to rely on this behavior. A future, optimized implementation may occasionally wake up more than n threads.

Note: an awakened thread does not actually return from its wait() call until it can reacquire the lock. Since notify() does not release the lock, its caller should.

notify_all()

Wake up all threads waiting on this condition. This method acts like notify(), but wakes up all waiting threads instead of one. If the calling thread has not acquired the lock when this method is called, a RuntimeError is raised.

17.1.6. Semaphore Objects

This is one of the oldest synchronization primitives in the history of computer science, invented by the early Dutch computer scientist Edsger W. Dijkstra (he used the names P() and V() instead of acquire() and release()).

信号量管理内部计数器,每个acquire()调用递减,每个release()调用递增。计数器永远不会低于零;当acquire()发现它为零时,它阻塞,等待其他线程调用release()

Semaphores还支持context management protocol

class threading.Semaphore(value=1)

这个类实现了信号量对象。信号量管理表示release()调用数减去acquire()调用数加上一个初始值的计数器。acquire()方法将会阻塞直到它可以在返回时计数器不是负数。如果没有给出,value默认为1。

可选参数给出内部计数器的初始;它默认为1If the value given is less than 0, ValueError is raised.

在版本3.3中更改:从工厂函数更改为类。

acquire(blocking=True, timeout=None)

Acquire a semaphore.

When invoked without arguments: if the internal counter is larger than zero on entry, decrement it by one and return immediately. If it is zero on entry, block, waiting until some other thread has called release() to make it larger than zero. This is done with proper interlocking so that if multiple acquire() calls are blocked, release() will wake exactly one of them up. The implementation may pick one at random, so the order in which blocked threads are awakened should not be relied on. 返回true(或无限期块)。

When invoked with blocking set to false, do not block. 如果没有参数的调用将阻塞,立即返回false;否则,做与没有参数调用时相同的事情,并返回true。

当以超时调用非None时,它将至多阻止超时秒。如果在该时间间隔内未成功完成捕获,则返回false。否则返回true。

在版本3.2中更改: 超时参数是新的。

release()

Release a semaphore, incrementing the internal counter by one. When it was zero on entry and another thread is waiting for it to become larger than zero again, wake up that thread.

class threading.BoundedSemaphore(value=1)

类实现有界信号对象。一个有界信号量会确保它当前的值不超过它的初始值。如果超过,则引发ValueError在大部分情况下,信号量用于守护有限容量的资源。如果信号量被释放太多次,它是一种有bug的迹象。如果没有给出,value默认为1。

在版本3.3中更改:从工厂函数更改为类。

17.1.6.1. Semaphore Example

Semaphores are often used to guard resources with limited capacity, for example, a database server. In any situation where the size of the resource is fixed, you should use a bounded semaphore. Before spawning any worker threads, your main thread would initialize the semaphore:

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

Once spawned, worker threads call the semaphore’s acquire and release methods when they need to connect to the server:

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

The use of a bounded semaphore reduces the chance that a programming error which causes the semaphore to be released more than it’s acquired will go undetected.

17.1.7. Event Objects

事件对象是线程间最简单的通信机制之一:线程可以激活在一个事件对象上等待的其他线程

每个事件对象管理一个内部标志,可以在事件对象上调用set() 方法将内部标志设为true,调用 clear() 方法将内部标志重置为false。wait()方法将阻塞直至该标志为真。

class threading.Event

实现事件对象的类。一个event管理一个标志,该标志可以通过set()方法设置为真或通过clear()方法重新设置为假。wait()方法阻塞,直到标志为真。该标志最初为假。

在版本3.3中更改:从工厂函数更改为类。

is_set()

Return true if and only if the internal flag is true.

set()

Set the internal flag to true. All threads waiting for it to become true are awakened. Threads that call wait() once the flag is true will not block at all.

clear()

Reset the internal flag to false. Subsequently, threads calling wait() will block until set() is called to set the internal flag to true again.

wait(timeout=None)

Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs.

When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).

如果且仅当内部标志在等待调用之前或等待开始之后设置为true时,此方法才返回true,因此它将始终返回True,除非给出超时,并且操作超时。

在版本3.1中更改:以前,该方法始终返回None

17.1.8. Timer Objects

这个类表示一个动作应该在一个特定的时间之后运行 — 也就是一个计时器。TimerThread的子类, 因此也可以使用函数创建自定义线程

Timers通过调用它们的start()方法作为线程启动。timer可以通过调用cancel()方法(在它的动作开始之前)停止。timer在执行它的动作之前等待的时间间隔可能与用户指定的时间间隔不完全相同。

例如:

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)

创建一个timer,在interval秒过去之后,它将以参数args和关键字参数kwargs运行function如果args为None(默认值),则将使用空列表。如果kwargs为None(默认值),则将使用空的字典。

在版本3.3中更改:从工厂函数更改为类。

cancel()

停止timer,并取消timer动作的执行。这只在timer仍然处于等待阶段时才工作。

17.1.9. Barrier Objects

版本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)

参与方创建障碍对象线程数。提供时,操作是可释放时由其中一个线程调用的调用。timeout是对wait()方法未指定的默认超时值。

wait(timeout=None)

通过障碍。当所有线程方面的屏障都调用了这个函数,它们都被同时释放。如果提供了超时,它优先于提供给类构造函数的任何内容。

返回值是范围为0至各方 - 1的整数,每个线程不同。这可以用于选择线程做一些特殊的内务处理,例如。

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

如果向构造函数提供操作,则其中一个线程将在释放之前调用它。如果这个调用引发一个错误,那么屏障就进入破坏状态。

如果呼叫超时,屏障被置于断开状态。

如果在线程等待时障碍被破坏或重置,此方法可能引发BrokenBarrierError异常。

reset()

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

注意,如果有其他线程的状态未知,使用此函数可能需要一些外部同步。如果一个障碍被打破,最好只是离开它并创造一个新的。

abort()

将障碍物置于破碎状态。这会导致对wait()的任何活动或未来调用失败,并返回BrokenBarrierError使用这个例如如果一个需要中止,以避免死锁应用程序。

可能优选的是简单地创建具有敏感的超时值的障碍以自动防止线程中的一个线程变坏。

parties

通过屏障所需的螺纹数。

n_waiting

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

broken

如果障碍处于中断状态,则为True的布尔值。

exception threading.BrokenBarrierError

Barrier对象重置或断开时,会引发此异常(RuntimeError的子类)。

17.1.10. Using locks, conditions, and semaphores in the with statement

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

with some_lock:
    # do something...

等效于:

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

目前,LockRLockConditionSemaphoreBoundedSemaphore用作with语句上下文管理器。