Python 生产者消费者模型
生产者消费者模型介绍
为什么要使用生产者消费者模型
生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者和消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
生产者消费者模型实现
函数yield 方式
def producer(name, count, cons):
cons.send(None)
for i in range(count):
print(f"{name}, 生产了第{i}个包子")
cons.send(f"{name}, 第{i}个包子")
def consumer(name):
while True:
time.sleep(1)
n = yield
print(f"\033[1;32m{name} 吃了{n}\033[0m")
for i in range(1, 3):
c = consumer(f"消费者{i}")
producer(f"生产者{i}", 5, c)
多进程方式
实现一、
使用多进程+多进程模块中的Queue队列实现
import time
from multiprocessing import Process, Queue
def producer(name, q, count):
for i in range(count):
time.sleep(0.5)
d = f"生产者{name} 第{i}包子"
print(d)
q.put(d)
def consumer(name, q):
while True:
time.sleep(1)
if q.empty(): # 判断队列是否为空, 为空结束索取
break
print(f"\033[1;32m消费者{name} 吃了{q.get()}\033[0m")
if __name__ == '__main__':
queue = Queue()
for i in range(1, 3):
p = Process(target=producer, args=(i, queue, 10))
p.start()
for i in range(1, 6):
c = Process(target=consumer, args=(i, queue))
c.start()
print("主进程")
实现二、
使用多进程+多进程模块中的JoinableQueue队列实现
import time
from multiprocessing import Process, JoinableQueue
def producer(name, q, count):
for i in range(count):
time.sleep(0.5)
d = f"生产者{name} 第{i}包子"
print(d)
q.put(d)
q.join()
def consumer(name, q):
while True:
time.sleep(1)
print(f"\033[1;32m消费者{name} 吃了{q.get()}\033[0m")
q.task_done()
if __name__ == '__main__':
queue = JoinableQueue()
p_list = []
for i in range(1, 3):
p = Process(target=producer, args=(i, queue, 10))
p_list.append(p)
p.start()
for i in range(1, 6):
c = Process(target=consumer, args=(i, queue))
c.daemon = True
c.start()
for i in p_list:
i.join()
print("主进程")
多线程方式
queue 模块实现了多生产者、多消费者队列。这特别适用于消息必须安全地在多线程间交换的线程编程
def producer(name, count, q):
for i in range(count):
i = f"{name} 第{i}包子"
print(i)
q.put(i)
def consumer(name, q):
while True:
time.sleep(0.5)
if q.empty():
break
print(f"{name} 消费{q.get()}")
if __name__ == '__main__':
q = queue.Queue()
print(q.empty())
for i in range(1, 4):
p = Thread(target=producer, args=(f"生产者{i}", 10, q))
p.start()
for i in range(1, 6):
c = Thread(target=consumer, args=(f"消费者{i}", q))
c.start()
print("主进程")