# 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. 线程本地数据

线程本地数据是指值特定于具体线程的数据。要管理线程本地数据，只需创建 `local`（或其子类）的一个实例并在它上面存储属性：

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

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

class `threading.``local`

  表示线程本地数据的一个类。

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

## 17.1.2. Thread 对象

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

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

一旦线程活动启动，该线程被视为 '活着'。当其 `run()` 方法终止 —— 正常终止或者引发一个未处理的异常时，它将不再是活着。`is_alive()` 方法测试线程是否还活着。

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

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

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

注

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

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

有种可能是创建的是“虚拟的线程对象”。这些线程对象对应于“异质的线程”，它们是在threading模块之外启动的控制线程，例如直接从C代码中启动的线程。虚拟线程对象的功能有限；它们总是被认为是活的和守护进程的，并且不能`join()`。它们永远不会被删除，因为异质线程的终止不可能检测到。

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参数的可调用对象，如果存在，分别从args和kwargs参数获取顺序参数和关键字参数。

  `join`(timeout=None)

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

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

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

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

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

  `name`

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

  `getName`()
  `setName`()

    `name` 旧式的getter/setter API；请直接以属性使用它。

  `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代码（即使某些基于性能的库可能克服这个限制）。如果希望应用程序更好地利用多核机器的计算资源，建议使用`multiprocessing`或`concurrent.futures.ProcessPoolExecutor`。然而，如果你想并发地运行多个I/O密集的任务，threading仍然是一个合适的模型。

## 17.1.3. Lock 对象

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

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

Locks 还支持 上下文管理器协议。

当有多个线程被 `acquire()` 阻塞，等待状态变为 unlocked 时，只有一个线程在 `release()` 调用将状态重置为 unlocked 时可以继续；等待线程中的哪一个继续未被定义，并且在不同的实现中可能不一致。

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

class `threading.``Lock`

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

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

  `acquire`(blocking=True, timeout=-1)

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

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

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

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

    如果成功获取锁定，则返回值为`True`，如果未成功，则返回`False`（例如，如果超时过期）。

    版本3.2中的变化： 新增 timeout 参数。

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

  `release`()

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

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

    当在未锁定的锁上调用时，会引发`RuntimeError`。

    没有返回值。

## 17.1.4. RLock 对象

一个可重入所示一个同步原语，它可以被相同的线程获得多次。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()`

可重入锁也支持上下文管理器协议。

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 对象

Condition 变量总是与某种锁相关联；这个锁可以传入，否则将默认创建一个锁。传递一个锁进去主要用于几个 Condition 变量必须共享同一个锁的时候。锁是 Condition 对象的一部分：你不必单独跟踪它。

Condition 变量遵守上下文管理器协议：使用 `with` 语句获取关联的锁用于包围的语句块。`acquire()`和`release()`方法也调用相关锁的相应方法。

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

如果有正在等待的线程，`notify()` 方法唤醒等待 Condition 变量的其中一个线程。`notify_all()` 方法唤醒所有等待这个 Condition 变量的线程。

注意：`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()` 的 Condition 可能不再持有锁。这是多线程编程固有的。`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`。

    这种方法释放底层锁，然后阻塞，直到它被一个在另一个线程中调用相同 Condition 变量的 `notify()` 或 `notify_all()` 唤醒，或直到超时。一旦被唤醒或超时，它就会重新获得锁定并返回。

    当 timeout 参数存在而不是`None`时，它应该是一个浮点数，指定操作的超时（以秒为单位）（或其分数）。

    当底层的锁是 `RLock` 时，它不会使用其 `release()` 方法释放，因为当它以递归方式多次获取时，实际上可能无法解锁。相反，使用了 `RLock` 类的内部接口，即使多次递归获取它也能解锁它。然后，在重新获取锁时，使用另一个内部接口来恢复递归级别。

    返回值为 `True`，除非给定的 timeout 过期，在这种情况下为 `False`。

    在版本3.2中更改：以前，该方法始终返回`None`。

  `wait_for`(predicate, timeout=None)

    等待条件的计算结果为True。predicate 应为一个可调用对象，其结果将被解释为布尔值。可以提供 timeout，给出最大等待时间。

    这个方法可能会重复调用`wait()`，直到满足predicate，或直到发生超时。返回值是 predicate 的最后一个返回值，如果方法超时，则求值为 `False`。

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

        while not predicate():
            cv.wait()

    因此，与 `wait()` 一样适用相同的规则：必须在调用时保持锁定并在返回时重新获取。predicate是在加锁的情况下进行计算。

    版本3.2中的新功能。

  `notify`(n=1)

    默认情况下，唤醒一个等待此 Condition 的线程（如果有）。如果调用此方法时调用线程尚未获取到锁，则引发 `RuntimeError`。

    该方法最多唤醒等待这个 Condiction 变量的 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.

    注意：唤醒的线程实际上不会从其 `wait()` 调用返回，直到它可以重新获取锁定。由于 `notify()` 不释放锁，因此其调用者应该释放。

  `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 对象

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。

  可选参数给出内部计数器的初始值；它默认为`1`。If 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

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

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. 在`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`语句上下文管理器。