Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。不断的重复这一过程,从而解决复杂的同步问题。
除了上面画的acquire方法、 release方法、notify方法、wait方法外还有notifyAll方法,不过notifyAll方法不常用。
51cto博客上我看到一篇博文中,形象的以二人对话 (生产者-消费者模)来解释上面的具体理论。
其中空格哥对应原理图中的A函数 ,西米对应的B 函数,每句话是doing操作,空格哥未“doing” 前,西米需要一直等待。最后,你来我往,直到最后都release掉,对话结束。由于代码太长,我给个精简版的,模拟上面的对话:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#coding:utf-8 #---- Condition #---- 捉迷藏的游戏 import threading, time class Hider(threading.Thread): def __init__(self, cond, name): super(Hider, self).__init__() self.cond = cond self.name = name def run(self): time.sleep(1) #确保先运行Seeker中的方法 self.cond.acquire() #b print self.name + ': 我已经把眼睛蒙上了' self.cond.notify() self.cond.wait() #c #f print self.name + ': 我找到你了 ~_~' self.cond.notify() self.cond.release() #g print self.name + ': 我赢了' #h class Seeker(threading.Thread): def __init__(self, cond, name): super(Seeker, self).__init__() self.cond = cond self.name = name def run(self): self.cond.acquire() self.cond.wait() #a #释放对琐的占用,同时线程挂起在这里,直到被notify并重新占有琐。 #d print self.name + ': 我已经藏好了,你快来找我吧' self.cond.notify() self.cond.wait() #e #h self.cond.release() print self.name + ': 被你找到了,哎~~~' cond = threading.Condition() seeker = Seeker(cond, 'seeker') hider = Hider(cond, 'hider') seeker.start() hider.start() |
执行结果如下:
1 2 3 4 5 6 |
[root@361way condition]# python con3.py hider: 我已经把眼睛蒙上了 seeker: 我已经藏好了,你快来找我吧 hider: 我找到你了 ~_~ seeker: 被你找到了,哎~~~ hider: 我赢了 |
便于对比,这里再给一个无限循环的例子。经典的生产者与消费者问题:假设有一群生产者(Producer)和一群消费者(Consumer)通过一个市场来交互产品。生产者的”策略“是如果市场上剩余的产品少于1000个,那么就生产100个产品放到市场上;而消费者的”策略“是如果市场上剩余产品的数量多余100个,那么就消费3个产品。
用Condition解决生产者与消费者问题的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import threading import time class Producer(threading.Thread): def run(self): global count while True: if con.acquire(): if count > 1000: con.wait() else: count = count+100 msg = self.name+' produce 100, count=' + str(count) print msg con.notify() con.release() time.sleep(1) class Consumer(threading.Thread): def run(self): global count while True: if con.acquire(): if count |