python3从零学习-5.6.7、threading.py线程模块

源代码: Lib/threading.py

这个模块定义了以下函数:

threading.active_count()

    返回当前存活的线程类 Thread 对象。返回的计数等于 enumerate() 返回的列表长度。

threading.current_thread()

    返回当前对应调用者的控制线程的 Thread 对象。如果调用者的控制线程不是利用 threading 创建,会返回一个功能受限的虚拟线程对象。

threading.get_ident()

    返回当前线程的 “线程标识符”。它是一个非零的整数。它的值没有直接含义,主要是用作 magic cookie,比如作为含有线程相关数据的字典的索引。线程标识符可能会在线程退出,新线程创建时被复用。

threading.enumerate()

    以列表形式返回当前所有存活的 Thread 对象。 该列表包含守护线程,current_thread() 创建的虚拟线程对象和主线程。它不包含已终结的线程和尚未开始的线程。

threading.main_thread()

    返回主 Thread 对象。一般情况下,主线程是Python解释器开始时创建的线程。

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)的正整数值。如果没有指定大小,则使用0。如果不支持更改线程堆栈大小,则会引发RuntimeError。如果指定的堆栈大小无效,则会引发ValueError错误,并且堆栈大小未被修改。32 KiB是当前支持的最小堆栈大小值,以确保解释器本身有足够的堆栈空间。请注意,一些平台可能对堆栈大小的值有特殊的限制,例如要求最小堆栈大小> 32 KiB或要求以系统内存页面大小的倍数分配——平台文档应该参考更多信息(4个KiB页面是常见的;如果没有更具体的信息,建议使用4096的倍数作为堆栈大小)。可用性:Windows,带有POSIX线程的系统。

这个模块同时定义了以下常量:

threading.TIMEOUT_MAX

    阻塞函数( Lock.acquire(), RLock.acquire(), Condition.wait(), …)中形参 timeout 允许的最大值。传入超过这个值的 timeout 会抛出 OverflowError 异常。

线程对象

当线程对象一但被创建,其活动一定会因调用线程的 start() 方法开始。这会在独立的控制线程调用 run() 方法。

一旦线程活动开始,该线程会被认为是 ‘存活的’ 。当它的 run() 方法终结了(不管是正常的还是抛出未被处理的异常),就不是’存活的’。 is_alive() 方法用于检查线程是否存活。

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

线程有名字。名字可以传递给构造函数,也可以通过 name 属性读取或者修改。

一个线程可以被标记成一个“守护线程”。 这个标志的意义是,当剩下的线程都是守护线程时,整个 Python 程序将会退出。 初始值继承于创建线程。 这个标志可以通过 daemon 特征属性或者 daemon 构造器参数来设置。

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 参数将显式地设置该线程是否为守护模式。 如果是 None (默认值),线程将继承当前线程的守护模式属性。

    如果子类型重载了构造函数,它一定要确保在做任何事前,先发起调用基类构造器(Thread.__init__())。

    在 3.3 版更改: 加入 daemon 参数。

    start()

        开始线程活动。

        它在一个线程里最多只能被调用一次。它安排对象的 run() 方法在一个独立的控制进程中调用。

        如果同一个线程对象中调用这个方法的次数大于一次,会抛出 RuntimeError 。

    run()

        代表线程活动的方法。

        您可以在子类中重写此方法。标准的run()方法调用传递给对象构造函数的可调用对象作为目标参数(如果有的话),分别从args和kwargs参数中获取顺序参数和关键字参数。

    join(timeout=None)

        等待,直到线程终结。这会阻塞调用这个方法的线程,直到被调用 join() 的线程终结 – 不管是正常终结还是抛出未处理异常 – 或者直到发生超时,超时选项是可选的。

        当 timeout 参数存在而且不是 None 时,它应该是一个用于指定操作超时的以秒为单位的浮点数(或者分数)。因为 join() 总是返回 None ,所以你一定要在 join() 后调用 is_alive() 才能判断是否发生超时 – 如果线程仍然存活,则 join() 超时。

        当 timeout 参数不存在或者是 None ,这个操作会阻塞直到线程终结。

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

        如果尝试加入当前线程会导致死锁, join() 会引起 RuntimeError 异常。如果尝试 join() 一个尚未开始的线程,也会抛出相同的异常。

    name

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

    getName()

    setName()

        旧的 name 取值/设值 API;直接当做特征属性使用它。

    ident

        这个线程的 ‘线程标识符’,如果线程尚未开始则为 None 。这是个非零整数。参见 get_ident() 函数。当一个线程退出而另外一个线程被创建,线程标识符会被复用。即使线程退出后,仍可得到标识符。

    is_alive()

        返回线程是否存活。

        当 run() 方法刚开始直到 run() 方法刚结束,这个方法返回 True 。模块函数 enumerate() 返回包含所有存活线程的列表。

    daemon

        一个表示这个线程是(True)否(False)守护线程的布尔值。一定要在调用 start() 前设置好,不然会抛出 RuntimeError 。初始值继承于创建线程;主线程不是守护线程,因此主线程创建的所有线程默认都是 daemon = False。

        当没有存活的非守护线程时,整个Python程序才会退出。

    isDaemon()

    setDaemon()

        旧的 name 取值/设值 API;建议直接当做特征属性使用它。

CPython implementation detail: CPython下,因为 Global Interpreter Lock,一个时刻只有一个线程可以执行Python代码(尽管如此,某些性能导向的库可能会克服这个限制)。如果你想让你的应用更好的利用多核计算机的计算性能,推荐你使用 multiprocessing 或者 concurrent.futures.ProcessPoolExecutor 。但是如果你想同时运行多个I/O绑定任务,线程仍然是一个合适的模型。

锁对象

原始锁处于 “锁定” 或者 “非锁定” 两种状态之一。它被创建时为非锁定状态。它有两个基本方法, acquire() 和 release() 。当状态为非锁定时, acquire() 将状态改为 锁定 并立即返回。当状态是锁定时, acquire() 将阻塞至其他线程调用 release() 将其改为非锁定状态,然后 acquire() 调用重置其为锁定状态并返回。 release() 只在锁定状态下调用; 它将状态改为非锁定并立即返回。如果尝试释放一个非锁定的锁,则会引发 RuntimeError  异常。

当多个线程在 acquire() 等待状态转变为未锁定被阻塞,然后 release() 重置状态为未锁定时,只有一个线程能继续执行;至于哪个等待线程继续执行没有定义,并且会根据实现而不同。

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

class threading.Lock

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

    需要注意的是 Lock 其实是一个工厂函数,返回平台支持的具体锁类中最有效的版本的实例。

    acquire(blocking=True, timeout=-1)

        可以阻塞或非阻塞地获得锁。

        当调用时参数 blocking 设置为 True (缺省值),阻塞直到锁被释放,然后将锁锁定并返回 True 。

        在参数 blocking 被设置为 False 的情况下调用,将不会发生阻塞。如果调用时 blocking 设为 True 会阻塞,并立即返回 False ;否则,将锁锁定并返回 True。

        当浮点型 timeout 参数被设置为正值调用时,只要无法获得锁,将最多阻塞 timeout 设定的秒数。timeout 参数被设置为 -1 时将无限等待。当 blocking 为 false 时,timeout 指定的值将被忽略。

        如果成功获得锁,则返回 True,否则返回 False (例如发生 超时 的时候)。

        在 3.2 版更改: 新的 timeout 形参。

        在 3.2 版更改: 现在如果底层线程实现支持,则可以通过POSIX上的信号中断锁的获取。

    release()

        释放一个锁。这个方法可以在任何线程中调用,不单指获得锁的线程。

        当锁被锁定,将它重置为未锁定,并返回。如果其他线程正在等待这个锁解锁而被阻塞,只允许其中一个允许。

        在未锁定的锁调用时,会引发 RuntimeError 异常。

        没有返回值。

递归锁对象

重入锁是一个可以被同一个线程多次获取的同步基元组件。在内部,它在基元锁的锁定/非锁定状态上附加了 “所属线程” 和 “递归等级” 的概念。在锁定状态下,某些线程拥有锁 ; 在非锁定状态下, 没有线程拥有它。

若要锁定锁,线程调用其 acquire() 方法;一旦线程拥有了锁,方法将返回。若要解锁,线程调用 release() 方法。 acquire()/release() 对可以嵌套;只有最终 release() (最外面一对的 release() ) 将锁解开,才能让其他线程继续处理 acquire() 阻塞。

class threading.RLock

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

    需要注意的是 RLock 其实是一个工厂函数,返回平台支持的具体递归锁类中最有效的版本的实例。

    acquire(blocking=True, timeout=-1)

        可以阻塞或非阻塞地获得锁。

        当无参数调用时: 如果这个线程已经拥有锁,递归级别增加一,并立即返回。否则,如果其他线程拥有该锁,则阻塞至该锁解锁。一旦锁被解锁(不属于任何线程),则抢夺所有权,设置递归等级为一,并返回。如果多个线程被阻塞,等待锁被解锁,一次只有一个线程能抢到锁的所有权。在这种情况下,没有返回值。

    release()

        释放锁,自减递归等级。如果减到零,则将锁重置为非锁定状态(不被任何线程拥有),并且,如果其他线程正被阻塞着等待锁被解锁,则仅允许其中一个线程继续。如果自减后,递归等级仍然不是零,则锁保持锁定,仍由调用线程拥有。

        只有当前线程拥有锁才能调用这个方法。如果锁被释放后调用这个方法,会引起 RuntimeError 异常。

        没有返回值。

条件对象

class threading.Condition(lock=None)

    实现条件变量对象的类。一个条件变量对象允许一个或多个线程在被其它线程所通知之前进行等待。

    如果给出了非 None 的 lock 参数,则它必须为 Lock 或者 RLock 对象,并且它将被用作底层锁。否则,将会创建新的 RLock 对象,并将其用作底层锁。

    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)

        等待,直到条件计算为真。 predicate 应该是一个可调用对象而且它的返回值可被解释为一个布尔值。可以提供 timeout 参数给出最大等待时间。

        这个实用方法会重复地调用 wait() 直到满足判断式或者发生超时。返回值是判断式最后一个返回值,而且如果方法发生超时会返回 False 。

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

            while not predicate():

                cv.wait()

        因此,规则同样适用于 wait() :锁必须在被调用时保持获取,并在返回时重新获取。 随着锁定执行判断式。

    notify(n=1)

        默认唤醒一个等待这个条件的线程。如果调用线程在没有获得锁的情况下调用这个方法,会引发 RuntimeError 异常。

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

        当前实现中,如果至少有 n 个线程正在等待,准确唤醒 n 个线程。但是依赖这个行为并不安全。未来,优化的实现有时会唤醒超过 n 个线程。

        注意:被唤醒的线程实际上不会返回它调用的 wait() ,直到它可以重新获得锁。因为 notify() 不会释放锁,只有它的调用者应该这样做。

    notify_all()

        唤醒所有正在等待这个条件的线程。这个方法行为与 notify() 相似,但并不只唤醒单一线程,而是唤醒所有等待线程。如果调用线程在调用这个方法时没有获得锁,会引发 RuntimeError 异常。

信号量对象

class threading.Semaphore(value=1)

    该类实现信号量对象。信号量对象管理一个原子性的计数器,代表 release() 方法的调用次数减去 acquire() 的调用次数再加上一个初始值。如果需要, acquire() 方法将会阻塞直到可以返回而不会使得计数器变成负数。在没有显式给出 value 的值时,默认为1。

    可选参数 value 赋予内部计数器初始值,默认值为 1 。如果 value 被赋予小于0的值,将会引发 ValueError 异常。

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

    acquire(blocking=True, timeout=None)

        获取一个信号量。

    release()

        释放一个信号量,将内部计数器的值增加1。当计数器原先的值为0且有其它线程正在等待它再次大于0时,唤醒正在等待的线程。

class threading.BoundedSemaphore(value=1)

    该类实现有界信号量。有界信号量通过检查以确保它当前的值不会超过初始值。如果超过了初始值,将会引发 ValueError 异常。在大多情况下,信号量用于保护数量有限的资源。如果信号量被释放的次数过多,则表明出现了错误。没有指定时, value 的值默认为1。

事件对象

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

一个事件对象管理一个内部标志,调用 set() 方法可将其设置为true,调用 clear() 方法可将其设置为false,调用 wait() 方法将进入阻塞直到标志为true。

class threading.Event

    实现事件对象的类。事件对象管理一个内部标志,调用 set() 方法可将其设置为true。调用 clear() 方法可将其设置为false。调用 wait() 方法将进入阻塞直到标志为true。这个标志初始时为false。

    is_set()

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

    set()

        将内部标志设置为true。所有正在等待这个事件的线程将被唤醒。当标志为true时,调用 wait() 方法的线程不会被被阻塞。

    clear()

        将内部标志设置为false。之后调用 wait() 方法的线程将会被阻塞,直到调用 set() 方法将内部标志再次设置为true。

    wait(timeout=None)

        阻塞线程直到内部变量为true。如果调用时内部标志为true,将立即返回。否则将阻塞线程,直到调用 set() 方法将标志设置为true或者发生可选的超时。

        当提供了timeout参数且不是 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)

    创建一个定时器,在经过 interval 秒的间隔事件后,将会用参数 args 和关键字参数 kwargs 调用 function。如果 args 为 None (默认值),则会使用一个空列表。如果 kwargs 为 None (默认值),则会使用一个空字典。

    cancel()

        停止定时器并取消执行计时器将要执行的操作。仅当计时器仍处于等待状态时有效。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342