Condition
class threading.Condition(lock=None
这个类实现条件变量对象。条件变量允许一个或多个线程等待,知道它们被另一个线程唤醒。 如果给出了lock
参数而不是None
,则它必须是Lcok
或RLock
对象,并以它作为底层的锁。否则将默认创建一个RLock
对象。Condition
遵循上下文管理协议。 方法:acquire(*args) 获取锁。这个方法调用底层锁的相应方法。 release()
释放锁。这个方法调用底层锁的相应方法。wait(timeout=None)
线程挂起,等待被唤醒(其他线程的notify
方法)或者发生超时。调用该方法的线程必须先获得锁,否则引发RuntimeError
。 该方法会释放底层锁,然后阻塞,直到它被另一个线程中的相同条件变量的notify()
或notify_all()
方法唤醒,或者发生超时。一旦被唤醒或超时,它会重新获取锁并返回。 返回值为True
,如果给定timeout
并发生超时,则返回False
。 wait_for(predicate, timeout=None)
等待知道条件变量的返回值为True
。predicate
应该是一个返回值可以解释为布尔值的可调用对象。可以设置timeout
以给定最大等待时间。 该方法可以重复调用wait()
,直到predicate
的返回值解释为True
,或发生超时。该方法的返回值就是predicate
的最后一个返回值,如果发生超时,返回值为False
。 如果忽略超时功能,该方法大致相当于: while not predicate(): con.wait()
它与wait()
的规则相同:调用前必须先获取锁,阻塞时释放锁,并在被唤醒时重新获取锁并返回。
notify(n=1)
默认情况下,唤醒等待此条件变量的一个线程(如果有)。调用该方法的线程必须先获得锁,否则引发RuntimeError
。 该方法最多唤醒n个等待中的线程,如果没有线程在等待,它就是要给无动作的操作。注意:要被唤醒的线程实际上不会马上从wait()
方法返回(唤醒),而是等到它重新获取锁。这是因为notify()
并不会释放锁,需要线程本身来释放(通过wait()
或者release()
) notify_all()
此方法类似于notify()
,但唤醒的时所有等待的线程。 生产者与消费者 -- Condition版
场景:生产者一次性生产5个商品(生产过程中不可购买),之后通知消费者抢购,当商品卖完后,由消费者通知生产者开始生产。
# -*- coding:utf-8 -*-import threadingimport timenum = 0con = threading.Condition()class Producer(threading.Thread): """生产者""" def run(self): global num # 获取锁 con.acquire() while True: num += 1 print('生产了1个,现在有{0}个'.format(num)) time.sleep(1) if num >= 5: print('已达到5个,不再生产') # 唤醒消费者 con.notify() # 等待-释放锁;被唤醒-获取锁 con.wait() # 释放锁 con.release()class Customer(threading.Thread): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.money = 7 def run(self): global num while self.money > 0: # 由于场景是多个消费者进行抢购,如果将获取锁操作放在循环外(如生产者), # 那么一个消费者线程被唤醒时会锁住整个循环,无法实现另一个消费者的抢购。 # 在循环中添加一套"获取锁-释放锁",一个消费者购买完成后释放锁,其他消费者 # 就可以获取锁来参与购买。 con.acquire() if num <= 0: print('没货了,{0}通知生产者'.format( threading.current_thread().name)) con.notify() con.wait() self.money -= 1 num -= 1 print('{0}消费了1个, 剩余{1}个'.format( threading.current_thread().name, num)) con.release() time.sleep(1) print('{0}没钱了-回老家'.format(threading.current_thread().name))if __name__ == '__main__': p = Producer(daemon=True) c1 = Customer(name='Customer-1') c2 = Customer(name='Customer-2') p.start() c1.start() c2.start() c1.join() c2.join()
运行结果:
生产了1个,现在有1个生产了1个,现在有2个生产了1个,现在有3个生产了1个,现在有4个生产了1个,现在有5个已达到5个,不再生产Customer-1消费了1个, 剩余4个Customer-2消费了1个, 剩余3个Customer-1消费了1个, 剩余2个Customer-2消费了1个, 剩余1个Customer-1消费了1个, 剩余0个没货了,Customer-2通知生产者生产了1个,现在有1个生产了1个,现在有2个生产了1个,现在有3个生产了1个,现在有4个生产了1个,现在有5个已达到5个,不再生产Customer-1消费了1个, 剩余4个Customer-2消费了1个, 剩余3个Customer-1消费了1个, 剩余2个Customer-2消费了1个, 剩余1个Customer-1消费了1个, 剩余0个没货了,Customer-2通知生产者生产了1个,现在有1个生产了1个,现在有2个生产了1个,现在有3个生产了1个,现在有4个生产了1个,现在有5个已达到5个,不再生产Customer-1消费了1个, 剩余4个Customer-2消费了1个, 剩余3个Customer-2消费了1个, 剩余2个Customer-1消费了1个, 剩余1个Customer-1没钱了-回老家Customer-2消费了1个, 剩余0个没货了,Customer-2通知生产者生产了1个,现在有1个生产了1个,现在有2个生产了1个,现在有3个生产了1个,现在有4个生产了1个,现在有5个已达到5个,不再生产Customer-2消费了1个, 剩余4个Customer-2没钱了-回老家