01、condition -- 以古诗对答的方式看如何详细安排线程运行
--condition:用于多线程之间复杂的通信的一个锁,又称条件变量 例如:以一段对话为例: 小爱:天猫精灵,我们来对古诗吧 天猫精灵:好的 小爱:我住长江头 天猫精灵:君住长江尾 小爱:日日思君不见君 天猫精灵:共饮长江水 小爱:此水几时休 天猫精灵:此恨何时已 小爱:只愿君心似我心 天猫精灵:定不负相思意 --最原始的,继承线程重写,无法按照顺序进行一问一答。这种方式可以通过锁来实现一组对话的顺序。但是当对话变多之后就失效了 --这种锁的方式,表明锁不仅可以用于锁资源也可以用于锁住执行代码或输出结果 import threading # 小爱机器人 class XiaoAi(threading.Thread): def __init__(self, lock): super().__init__(name="小爱") self.lock = lock def run(self): self.lock.acquire() print("{}: 在".format(self.name)) self.lock.release() self.lock.acquire() print("{}: 好呀好呀".format(self.name)) self.lock.release() # 天猫精灵 class TianMao(threading.Thread): def __init__(self, lock): super().__init__(name="天猫精灵") self.lock = lock def run(self): self.lock.acquire() print("{}: 小爱同学".format(self.name)) self.lock.release() self.lock.acquire() print("{}: 我们来对古诗吧".format(self.name)) self.lock.release() if __name__ == '__main__': lock = threading.Lock() tianmao = TianMao(lock) xiaoai = XiaoAi(lock) tianmao.start() xiaoai.start() --真正使用 condition 进行排列线程执行顺序 --condition:方法说明介绍,打开源码,打开pycharm中structure 01、Condition实现了__enter__() 和 __exit__()两种方法,因此可以使用with的方式进行调用 02、Condition中默认使用的是 RLock() 可嵌套锁 if lock is None: lock = RLock() 03、wait 和 notify方法才是Condition的精髓 --wait(): 允许我们等待某个条件变量的通知,比如一个线程执行到某一步时进入等待通知的状态,知道获得到通知以后才继续执行某一段代码 --notify(): 发出通知 --使用condition控制线程: --线程启动顺序非常关键 --必须使用with 上下文管理器来初始化condition对象,否则会报错:RuntimeError: cannot wait on un-acquired lock --真正对话的代码: import threading from threading import Condition # 小爱机器人 class XiaoAi(threading.Thread): def __init__(self, cond): super().__init__(name="小爱") self.cond = cond def run(self): with self.cond: self.cond.wait() # 因为最开始不是小爱发言,所以一上来直接进入等待 print("{}: 在".format(self.name)) self.cond.notify() # self.cond.wait() print("{}: 好呀好呀".format(self.name)) self.cond.notify() self.cond.wait() print("{}: 君住长江尾".format(self.name)) self.cond.notify() self.cond.wait() print("{}: 共饮长江水".format(self.name)) self.cond.notify() # 天猫精灵 class TianMao(threading.Thread): def __init__(self, cond): super().__init__(name="天猫精灵") self.cond = cond def run(self): with self.cond: print("{}: 小爱同学".format(self.name)) self.cond.notify() # 发出通知 self.cond.wait() # 进入等待,等待小爱回应 print("{}: 我们来对古诗吧".format(self.name)) self.cond.notify() # 发出通知 self.cond.wait() # 进入等待,等待小爱回应 print("{}: 我住长江头".format(self.name)) self.cond.notify() # 发出通知 self.cond.wait() # 进入等待,等待小爱回应 print("{}: 日日思君不见君".format(self.name)) self.cond.notify() # 发出通知 self.cond.wait() # 进入等待,等待小爱回应 if __name__ == '__main__': cond = threading.Condition() tianmao = TianMao(cond) xiaoai = XiaoAi(cond) # 记住这里启动顺序非常重要,如果启动顺序出错,会由于没有条件变量变动的感知方,而导致条件变量不会继续变化,线程卡死 xiaoai.start() tianmao.start()02、为什么不使用with会出现报错 -- 从源码分析一下
--condition有两层锁,先释放一层锁再加一层锁 --一层锁在调用wait方法时被释放掉 --另一层锁在调用wait方法释放锁时加上去,并放入cond的等待队列self._waiters中。等待cond来释放这把锁