对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition. 帅醒 一.线程条件变量Condition相关函数介绍 acquire() — 线程锁,注意线程条件变量Condition中的所有相关函数使用必须在acquire() /release() 内部操作; release() — 释放锁,注意线程条件变量Condition中的所有相关函数使用必须在acquire() /release() 内部操作; wait(timeout) — 线程挂起(阻塞状态),直到收到一个notify通知或者超时才会被唤醒继续运行(超时参数默认不设置,可选填,类型是浮点数,单位是秒)。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError; notify(n=1) — 通知其他线程,那些挂起的线程接到这个通知之后会开始运行,缺省参数,默认是通知一个正等待通知的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError,notify()不会主动释放Lock; notifyAll() — 如果wait状态线程比较多,notifyAll的作用就是通知所有线程; 不要脸 二.线程条件变量Condition原理 在前面的文章已经介绍过互斥锁,主要作用是并行访问共享资源时,保护共享资源,防止出现脏数据。python 条件变量Condition也需要关联互斥锁,同时Condition自身提供了wait/notify/notifyAll方法,用于阻塞/通知其他并行线程,可以访问共享资源了。可以这么理解,Condition提供了一种多线程通信机制,假如线程1需要数据,那么线程1就阻塞等待,这时线程2就去制造数据,线程2制造好数据后,通知线程1可以去取数据了,然后线程1去获取数据。 张飞 三.线程条件变量Condition使用 案例一:成语接龙 复制代码 # !usr/bin/env python # -*- coding:utf-8 _*- """ @Author:何以解忧 @Blog(个人博客地址): shuopython.com @WeChat Official Account(微信公众号):猿说python @Github:www.github.com @File:python_.py @Time:2019/10/21 21:25 @Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累! """ # 导入线程模块 import threading # 创建条件变量condition con = threading.Condition() def thread_one(name): # 条件变量condition 线程上锁 con.acquire() print("{}:成语接龙准备好了吗".format(name)) # 唤醒正在等待(wait)的线程 con.notify() # 等待对方回应消息,使用wait阻塞线程,等待对方通过notify唤醒本线程 con.wait() print("{}:一干二净".format(name)) # 唤醒对方 con.notify() # 等待消息答应 con.wait() print("{}:一天就知道看抖音美女,给你来个简单点的,来了:毛手毛脚".format(name)) # 唤醒对方 con.notify() # 等待消息答应 con.wait() print("{}:哟哟哟,不错不错!".format(name)) # 唤醒对方 con.notify() # 条件变量condition 线程释放锁 con.release() def thread_two(name): # 条件变量condition 线程上锁 con.acquire() # wait阻塞状态,等待其他线程通过notify唤醒本线程 con.wait() print("{}:准备好了~开始吧!".format(name)) # 唤醒对方 con.notify() # 等待消息答应 con.wait() print("{}:净你妹啊,没法接...来个简单点的...".format(name)) # 唤醒对方 con.notify() # 等待消息答应 con.wait() print("{}:嘿,这个我知道:脚踏实地".format(name)) # 唤醒对方 con.notify() con.release() if __name__ == "__main__": # 创建并初始化线程 t1 = threading.Thread(target=thread_one,args=("A")) t2 = threading.Thread(target=thread_two,args=("B")) # 启动线程 -- 注意线程启动顺序,启动顺序很重要 t2.start() t1.start() # 阻塞主线程,等待子线程结束 t1.join() t2.join() print("程序结束!") 复制代码 输出结果: 复制代码 A:成语接龙准备好了吗 B:准备好了~开始吧! A:一干二净 B:净你妹啊,没法接...来个简单点的... A:一天就知道看抖音美女,给你来个简单点的,来了:毛手毛脚 B:嘿,这个我知道:脚踏实地 A:哟哟哟,不错不错! 程序结束! 复制代码 思考 案例二:生产者与消费者模式,以吃火锅为例:一盘老肉片有10块肉,吃完了又重新往锅里加…. 生产者:往锅里加老肉片,每次加一盘(10块); 消费者:吃煮熟的肉片,没吃一片,肉片数量减一,吃完为止; 复制代码 # 导入线程模块 import threading import time # 创建条件变量condition con = threading.Condition() meat_num = 0 def thread_consumers(): # 条件变量condition 线程上锁 con.acquire() # 全局变量声明关键字 global global meat_num meat_num = 0 # 等待肉片下锅煮熟 con.wait() while True: print("我来一块肉片...") meat_num -= 1 print("剩余肉片数量:%d"%meat_num) time.sleep(0.5) if meat_num == 0: # 肉片吃光了,通知老板添加肉片 print("老板,再来一份老肉片...") con.notify() # 肉片吃光了,等待肉片 con.wait() # 条件变量condition 线程释放锁 con.release() def thread_producer(): # 条件变量condition 线程上锁 con.acquire() # 全局变量声明关键字 global global meat_num # 肉片熟了,可以开始吃了 meat_num = 10 print("肉片熟了,可以开始吃了...") con.notify() while True: # 阻塞函数,等待肉片吃完的通知 con.wait() meat_num = 10 # 添加肉片完成,可以继续开吃 print("添加肉片成功!当前肉片数量:%d"%meat_num) time.sleep(1) con.notify() con.release() if __name__ == "__main__": # 创建并初始化线程 t1 = threading.Thread(target=thread_producer) t2 = threading.Thread(target=thread_consumers) # 启动线程 -- 注意线程启动顺序,启动顺序很重要 t2.start() t1.start() # 阻塞主线程,等待子线程结束 t1.join() t2.join() print("程序结束!") 复制代码 输出结果: 复制代码 肉片熟了,可以开始吃了... 我来一块肉片... 剩余肉片数量:9 我来一块肉片... 剩余肉片数量:8 我来一块肉片... 剩余肉片数量:7 我来一块肉片... 剩余肉片数量:6 我来一块肉片... 剩余肉片数量:5 我来一块肉片... 剩余肉片数量:4 我来一块肉片... 剩余肉片数量:3 我来一块肉片... 剩余肉片数量:2 我来一块肉片... 剩余肉片数量:1 我来一块肉片... 剩余肉片数量:0 老板,再来一份老肉片... 添加肉片成功!当前肉片数量:10 我来一块肉片... 剩余肉片数量:9 我来一块肉片... 剩余肉片数量:8 我来一块肉片... 剩余肉片数量:7 ............. 复制代码 注意: 1.全局变量要声明关键字 global; 2.注意线程的启动顺序,这个很重要; 四.重点总结 注意线程互斥锁Lock/线程事件Event/线程条件变量Condition三者的区别,场景不同,使用方式也不同,前两者一般可以作为简单的线程交互,线程条件变量Condition可以用于比较复杂的线程交互! 猜你喜欢: 1.python线程创建和参数传递 2.python线程互斥锁Lock 3.python线程事件Event 4.python return逻辑判断表达式 转载请注明:猿说Python » python条件变量Conditionhttps://www.cnblogs.com/shuopython/p/11949666.html