python-生产者消费者模型
生产者和消费者模式是多线程开发中经常见到的一种模式。生产者的线程专门用来生产一些数据,然后存放到一个中间的变量中。消费者再从这个中间的变量中取出数据进行消费。通过生产者和消费者模式,可以让代码达到高内聚低耦合的目标,程序分工更加明确,线程更加方便管理。下面分别展示Lock版本和 Condition版本的生产者和消费者模型(生产者只能生产10次)。
Lock版本的生产者和消费者模式:
import threading
import random
import time
gMoney = 0
gLock = threading.Lock()
gTimes = 0
class Producer(threading.Thread):
def run(self) -> None: # 箭头代表函数值返回的是None
global gMoney # 更改了全局变量需要声明
global gTimes
while True:
time.sleep(1)
gLock.acquire() # 上锁
if gTimes >= 10: # 生产者只能生产10次
gLock.release() # 在退出循环之前释放锁
break # 退出循环
money = random.randint(0, 100)
gMoney += money
gTimes += 1
print("%s生产了%d元钱"%(threading.current_thread().name,money))
gLock.release() # 释放锁
class Consumer(threading.Thread):
def run(self) -> None:
global gMoney
while True:
time.sleep(1)
gLock.acquire()
money = random.randint(0,100)
if gMoney >= money: # 判断钱够不够
gMoney -= money
print("%s消费了%d元钱"%(threading.current_thread().name,money))
else:
if gTimes >= 10: # 生产者已经不再生产
gLock.release()
break
print("%s想消费%d元钱,但是余额只有%d"%(threading.current_thread().name,money,gMoney))
gLock.release()
def main():
for x in range(5): # 创建5个生产者线程
th = Producer(name="生产者%d号"%x)
th.start()
for x in range(5): # 创建5个消费者线程
th = Consumer(name="消费者%d号"%x)
th.start()
if __name__ == '__main__':
main()
输出结果:
生产者0号生产了4元钱
生产者1号生产了22元钱
生产者3号生产了6元钱
消费者0号想消费72元钱,但是余额只有32
生产者4号生产了53元钱
生产者2号生产了30元钱
消费者4号消费了1元钱
消费者1号消费了39元钱
消费者3号消费了58元钱
消费者2号想消费40元钱,但是余额只有17
生产者0号生产了80元钱
消费者0号消费了71元钱
生产者3号生产了84元钱
生产者1号生产了93元钱
消费者3号消费了20元钱
消费者4号消费了92元钱
生产者2号生产了22元钱
消费者2号消费了31元钱
生产者4号生产了73元钱
消费者1号消费了41元钱
消费者0号消费了8元钱
消费者3号消费了13元钱
消费者4号消费了0元钱
消费者2号消费了72元钱
消费者0号消费了1元钱
Process finished with exit code 0
Condition版本的生产者和消费者模式:
Lock版本的生产者与消费者模式可以正常的运行。但是存在一个不足,在消费者中,总是通过while True死循环并且上锁的方式去判断钱够不够。上锁是一个很耗费CPU资源的行为。因此这种方式不是最好的。还有一种更好的方式便是使用threading.Condition来实现。threading.Condition可以在没有数据的时候处于阻塞等待状态。一旦有合适的数据了,还可以使用notify相关的函数来通知其他处于等待状态的线程。这样就可以不用做一些无用的上锁和解锁的操作。可以提高程序的性能。首先对threading.Condition相关的函数做个介绍,threading.Condition类似threading.Lock,可以在修改全局数据的时候进行上锁,也可以在修改完毕后进行解锁。以下将一些常用的函数做个简单的介绍:
- acquire:上锁。
- release:解锁。
- wait:将当前线程处于等待状态,并且会释放锁。可以被其他线程使用notify和notify_all函数唤醒。被唤醒后会继续等待上锁,上锁后继续执行下面的代码。
- notify:通知某个正在等待的线程,默认是第1个等待的线程。
- notify_all:通知所有正在等待的线程。notify和notify_all不会释放锁。并且需要在release之前调用。
代码如下:
import threading
import random
import time
gMoney = 0
gCondition = threading.Condition()
gTimes = 0
class Producer(threading.Thread):
def run(self) -> None:
global gMoney
global gTimes
while True:
time.sleep(1)
gCondition.acquire()
if gTimes >= 10:
gCondition.release()
break
money = random.randint(0, 100)
gMoney += money
gTimes += 1
print("%s生产了%d元钱,剩余%d元钱"%(threading.current_thread().name,money,gMoney))
gCondition.notify_all()
gCondition.release()
class Consumer(threading.Thread):
def run(self) -> None:
global gMoney
while True:
time.sleep(1)
gCondition.acquire()
money = random.randint(0,100)
while gMoney < money:
if gTimes >= 10:
print("%s想消费%d元钱,但是余额只有%d元钱了,并且生产者已经不再生产了!"%(threading.current_thread().name,money,gMoney))
gCondition.release()
return # 一次性将整个函数全部返回
print("%s想消费%d元钱,但是余额只有%d元钱了,消费失败!"%(threading.current_thread().name,money,gMoney))
gCondition.wait()
gMoney -= money
print("%s消费了%d元钱,剩余%d元钱"%(threading.current_thread().name,money,gMoney))
gCondition.release()
def main():
for x in range(5):
th = Producer(name="生产者%d号"%x)
th.start()
for x in range(5):
th = Consumer(name="消费者%d号"%x)
th.start()
if __name__ == '__main__':
main()
输出结果:
生产者2号生产了18元钱,剩余18元钱
生产者3号生产了71元钱,剩余89元钱
消费者3号消费了16元钱,剩余73元钱
生产者4号生产了16元钱,剩余89元钱
生产者1号生产了52元钱,剩余141元钱
消费者4号消费了93元钱,剩余48元钱
消费者0号想消费98元钱,但是余额只有48元钱了,消费失败!
消费者1号想消费49元钱,但是余额只有48元钱了,消费失败!
消费者2号消费了18元钱,剩余30元钱
生产者0号生产了31元钱,剩余61元钱
消费者0号想消费98元钱,但是余额只有61元钱了,消费失败!
消费者1号消费了49元钱,剩余12元钱
消费者4号想消费28元钱,但是余额只有12元钱了,消费失败!
生产者2号生产了42元钱,剩余54元钱
消费者0号想消费98元钱,但是余额只有54元钱了,消费失败!
生产者4号生产了31元钱,剩余85元钱
消费者0号想消费98元钱,但是余额只有85元钱了,消费失败!
生产者1号生产了52元钱,剩余137元钱
消费者0号消费了98元钱,剩余39元钱
消费者4号消费了28元钱,剩余11元钱
消费者3号想消费76元钱,但是余额只有11元钱了,消费失败!
生产者3号生产了87元钱,剩余98元钱
生产者0号生产了59元钱,剩余157元钱
消费者3号消费了76元钱,剩余81元钱
消费者1号消费了5元钱,剩余76元钱
消费者2号消费了7元钱,剩余69元钱
消费者3号消费了55元钱,剩余14元钱
消费者4号想消费55元钱,但是余额只有14元钱了,并且生产者已经不再生产了!
消费者1号想消费94元钱,但是余额只有14元钱了,并且生产者已经不再生产了!
消费者0号想消费50元钱,但是余额只有14元钱了,并且生产者已经不再生产了!
消费者2号想消费52元钱,但是余额只有14元钱了,并且生产者已经不再生产了!
消费者3号想消费59元钱,但是余额只有14元钱了,并且生产者已经不再生产了!
Process finished with exit code 0
生产者消费者模型是学习多线程的基础,我还写过一个多线程的案例——多线程下载王者荣耀高清壁纸(过程超详细)这是链接:,核心也是生产者消费者模型,大家可以看完这篇文章后再看一下那个案例,对理解多线程有很大帮助!!
♥♥♥希望对大家有所帮助!♥♥♥