16.2. threading — 更高级的线程接口

源代码: Lib/threading.py


此模块构造更高级线程接口,基于更低级 thread 模块。另请参阅 mutex and Queue 模块。

The dummy_threading 模块的提供是为当 threading 无法使用由于 thread 缺失。

注意

Starting with Python 2.6, this module provides PEP 8 compliant aliases and properties to replace the camelCase names that were inspired by Java’s threading API. This updated API is compatible with that of the multiprocessing module. However, no schedule has been set for the deprecation of the camelCase names and they remain fully supported in both Python 2.x and 3.x.

注意

Starting with Python 2.5, several Thread methods raise RuntimeError 而不是 AssertionError if called erroneously.

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

This module defines the following functions and objects:

threading. active_count ( )
threading. activeCount ( )

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

2.6 版改变: 添加 active_count() spelling.

threading. 条件 ( )

A factory function that returns a new condition variable object. A condition variable allows one or more threads to wait until they are notified by another thread.

条件对象 .

threading. current_thread ( )
threading. currentThread ( )

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

2.6 版改变: 添加 current_thread() spelling.

threading. enumerate ( )

返回列表为所有 Thread objects currently alive. The list includes daemonic threads, dummy thread objects created by current_thread() , and the main thread. It excludes terminated threads and threads that have not yet been started.

threading. 事件 ( )

A factory function that returns a new event object. An event manages a flag that can be set to true with the set() 方法和重置为 False 采用 clear() 方法。 wait() 方法阻塞直到标志为 True。

事件对象 .

class threading. local

A class that represents thread-local data. Thread-local data are data whose values are thread specific. To manage thread-local data, just create an instance of local (或子类) 并在其中存储属性:

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

实例的值异于单独线程。

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

2.4 版新增。

threading. ( )

A factory function that returns a new primitive lock object. Once a thread has acquired it, subsequent attempts to acquire it block, until it is released; any thread may release it.

锁对象 .

threading. RLock ( )

A factory function that returns a new reentrant lock object. A reentrant lock must be released by the thread that acquired it. Once a thread has acquired a reentrant lock, the same thread may acquire it again without blocking; the thread must release it once for each time it has acquired it.

RLock 对象 .

threading. 信号量 ( [ ] )

A factory function that returns a new semaphore object. A semaphore manages a counter representing the number of release() 调用减数 acquire() 调用,加初始值。 acquire() 方法阻塞若有必要直到它可以在不用使计数器为负的情况下返回。若不给定, value 默认为 1。

信号量对象 .

threading. BoundedSemaphore ( [ ] )

A factory function that returns a new bounded semaphore object. A bounded semaphore checks to make sure its current value doesn’t exceed its initial value. If it does, ValueError 被引发。在大多数情况下,信号量用于守卫容量有限的资源。若释放信号量太多次,有 Bug 迹象。若不给定, value 默认为 1。

class threading. Thread

A class that represents a thread of control. This class can be safely subclassed in a limited fashion.

线程对象 .

class threading. Timer

A thread that executes a function after a specified interval has passed.

计时器对象 .

threading. settrace ( func )

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

2.3 版新增。

threading. setprofile ( func )

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

2.3 版新增。

threading. stack_size ( [ size ] )

返回创建新线程时使用的线程堆栈大小。可选 size 自变量指定用于随后创建线程的堆栈大小,且必须为 0 (使用平台或配置默认的) 或至少 32,768 (32 KB) 的正整数值。若 size 未指定,使用 0。若不支持改变线程堆栈大小, ThreadError 被引发。若指定堆栈大小无效, ValueError is raised and the stack size is unmodified. 32kB is currently the minimum supported stack size value to guarantee sufficient stack space for the interpreter itself. Note that some platforms may have particular restrictions on values for the stack size, such as requiring a minimum stack size > 32kB or requiring allocation in multiples of the system memory page size - platform documentation should be referred to for more information (4kB pages are common; using multiples of 4096 for the stack size is the suggested approach in the absence of more specific information). Availability: Windows, systems with POSIX threads.

2.5 版新增。

exception threading. ThreadError

Raised for various threading-related errors as described below. Note that many interfaces use RuntimeError 而不是 ThreadError .

Detailed interfaces for the objects are documented below.

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

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

16.2.1. 线程对象

This class represents an activity that is run in a separate thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() 方法在子类中。不应覆盖子类中的其它方法 (除构造函数外)。换句话说, only 覆写 __init__() and run() 方法对于此类。

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

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

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

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

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

注意

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

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

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

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

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

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

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

name 是线程名称。默认情况下,唯一名称构造形式为 Thread- N 其中 N 是小十进制数。

args 是援引目标的自变量元组。默认为 () .

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

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

start ( )

启动线程活动。

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

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

run ( )

表示线程活动的方法。

可以在子类中覆盖此方法。标准 run() 方法援引传递给对象构造函数的可调用对象作为 target argument, if any, with sequential and keyword arguments taken from the args and kwargs 自变量,分别。

join ( [ timeout ] )

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

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

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

线程可以 join() 多次。

join() 引发 RuntimeError 若试图 join 当前线程,因为这会导致死锁。它也会出错当 join() a thread before it has been started and attempts to do so raises the same exception.

名称

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

2.6 版新增。

getName ( )
setName ( )

Pre-2.6 API for name .

ident

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

2.6 版新增。

is_alive ( )
isAlive ( )

返回线程是否存活。

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

2.6 版改变: 添加 is_alive() spelling.

daemon

A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before start() 被调用,否则 RuntimeError 被引发。其初始值继承自创建线程;主线程不是守护线程,因此,在主线程中创建的所有线程默认为 daemon = False .

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

2.6 版新增。

isDaemon ( )
setDaemon ( )

Pre-2.6 API for daemon .

16.2.2. 锁对象

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

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

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

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

Lock. acquire ( [ blocking ] )

获得锁,阻塞或非阻塞。

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

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

Lock. release ( )

Release a lock.

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

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

没有返回值。

locked ( )
返回 True 若获得锁。

16.2.3. RLock 对象

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

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

RLock. acquire ( [ blocking=1 ] )

获得锁,阻塞或非阻塞。

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

当援引采用 blocking argument set to true, do the same thing as when called without arguments, and return true.

当援引采用 blocking argument set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true.

RLock. release ( )

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

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

没有返回值。

16.2.4. 条件对象

A condition variable is always associated with some kind of lock; this can be passed in or one will be created by default. (Passing one in is useful when several condition variables must share the same lock.)

A condition variable has acquire() and release() methods that call the corresponding methods of the associated lock. It also has a wait() 方法,和 notify() and notifyAll() methods. These three must only be called when the calling thread has acquired the lock, otherwise a RuntimeError 被引发。

The wait() method releases the lock, and then blocks until it is awakened by a notify() or notifyAll() call for the same condition variable in another thread. Once awakened, it re-acquires the lock and returns. It is also possible to specify a timeout.

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

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

Tip: 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() 重复直到它们看到期望状态,而修改状态的线程会调用 notify() or notifyAll() 当它们改变状态时,以这种方式,它可能是某个等待者所期望的状态。例如,以下代码是具有不受限制缓冲容量的一般生产者/消费者情况:

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

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

class threading. 条件 ( [ lock ] )

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

acquire ( *args )

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

release ( )

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

wait ( [ timeout ] )

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

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

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

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

notify ( n=1 )

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

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

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

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

notify_all ( )
notifyAll ( )

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

2.6 版改变: 添加 notify_all() spelling.

16.2.5. 信号量对象

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 P() and V() 而不是 acquire() and release() ).

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

class threading. 信号量 ( [ ] )

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

acquire ( [ blocking ] )

获得信号量。

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. There is no return value in this case.

当被援引采用 blocking set to true, do the same thing as when called without arguments, and return true.

当被援引采用 blocking set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true.

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.

16.2.5.1. Semaphore 范例

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

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

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

pool_sema.acquire()
conn = connectdb()
... use connection ...
conn.close()
pool_sema.release()
					

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

16.2.6. 事件对象

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

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

class threading. 事件

The internal flag is initially false.

is_set ( )
isSet ( )

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

2.6 版改变: 添加 is_set() spelling.

set ( )

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

clear ( )

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

wait ( [ timeout ] )

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

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

This method returns the internal flag on exit, so it will always return True 除了有给定 timeout (超时),且操作超时。

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

16.2.7. 计时器对象

此类表示仅在经过一定数量时间后才应运行的动作 — 计时器。 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=[] , kwargs={} )

创建计时器将运行 function 采用自变量 args 和关键词自变量 kwargs ,后于 interval seconds have passed.

cancel ( )

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

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

由此模块提供的所有对象拥有 acquire() and release() 方法可以用作上下文管理器对于 with 语句。 acquire() 方法将被调用当进入块时,和 release() will be called when the block is exited.

目前, Lock , RLock , Condition , Semaphore ,和 BoundedSemaphore 对象可以用作 with statement context managers. For example:

import threading
some_rlock = threading.RLock()
with some_rlock:
    print "some_rlock is locked while this executes"
					

16.2.9. Importing in threaded code

While the import machinery is thread-safe, there are two key restrictions on threaded imports due to inherent limitations in the way that thread-safety is provided:

  • Firstly, other than in the main module, an import should not have the side effect of spawning a new thread and then waiting for that thread in any way. Failing to abide by this restriction can lead to a deadlock if the spawned thread directly or indirectly attempts to import a module.

  • Secondly, all import attempts must be completed before the interpreter starts shutting itself down. This can be most easily achieved by only performing imports from non-daemon threads created through the threading module. Daemon threads and threads created directly with the thread module will require some other form of synchronization to ensure they do not attempt imports after system shutdown has commenced. Failure to abide by this restriction will lead to intermittent exceptions and crashes during interpreter shutdown (as the late imports attempt to access machinery which is no longer in a valid state).