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来释放这把锁