多线程实现
多线程实现生产者消费者模型的逻辑十分简单,生产者与消费者之间通过队列来进行通讯,所以生产者不用等待消费者消费,直接丢给队列,同理,消费者也是一样,不用通过生产者取得数据,而是从队列里面拿取数据。这样,队列就相当于一个缓冲区,一个容器,平衡生产者与消费者的处理能力:
import random
from threading import Thread
from queue import Queue
class Producer(Thread):
def __init__(self, name, q):
super().__init__()
self.name = name
self.q = q
def run(self):
while True:
item = random.randint(1, 99)
self.q.put(item)
print('product: {}'.format(item))
class Consumer(Thread):
def __init__(self, name, q):
super().__init__()
self.name = name
self.q = q
def run(self):
while True:
item = self.q.get()
print('consum: {}'.format(item))
self.q.task_done()
if __name__ == '__main__':
q = Queue(10)
q.join()
p = Producer('p1', q)
c = Consumer('c1', q)
p.start()
c.start()
输出:
product: 14
product: 58
product: 8
product: 96
consum: 14
product: 93
product: 87
product: 88
product: 38
consum: 58
consum: 8
consum: 96
consum: 93
consum: 87
consum: 88
consum: 38
product: 21
consum: 21
...
多进程实现
多进程实现生产者消费者模型的代码与多线程版本类似:
import random
from multiprocessing import Process, Queue
class Producer(Process):
def __init__(self, name, q):
super().__init__()
self.name = name
self.q = q
def run(self):
while True:
item = random.randint(0, 99)
self.q.put(item)
print('product: {}'.format(item))
class Consumer(Process):
def __init__(self, name, q):
super().__init__()
self.name = name
self.q = q
def run(self):
while True:
item = self.q.get()
print('consum: {}'.format(item))
if __name__ == '__main__':
q = Queue(10)
p = Producer('p1', q)
c = Consumer('c1', q)
p.start()
c.start()
输出:
product: 47
product: 98
product: 43
product: 91
product: 70
product: 78
product: 14
product: 7
product: 72
product: 86
consum: 47
product: 89
consum: 98
consum: 43
...
生成器实现
def consumer():
while True:
item = yield
print('consume {}'.format(item))
def producer():
c.send(None) # 激活消费者生成器
while True:
item = random.randint(0, 99)
print('product {}'.format(item))
c.send(item)
c = consumer() # 消费者生成器
producer() # 生产者函数
输出如下:
product 0
consume 0
product 91
consume 91
product 44
consume 44
product 68
consume 68
product 43
consume 43
....
我们也可以交换send和yield的位置,让消费者向生产者请求数据,代码如下:
def consumer():
while True:
item = p.send(None)
if item is None:
print('...')
print('consume {}'.format(item))
def producer():
while True:
item = random.randint(0, 99)
print('product {}'.format(item))
yield item
p = producer() # 生产者生成器
consumer() # 消费者函数
也能够得到期望的输出:
product 34
consume 34
product 83
consume 83
product 40
consume 40
product 45
consume 45
...
通过生成器实现生产者消费者模型,CPU的有效利用率理论上能达到100%。若通过多线程来实现生产者消费者模型,queue会在full或empty时候阻塞;若通过多进程来实现生产者消费者模型,进程间的创建、切换、销毁要耗费大量CPU资源。