生产者-消费者的协程

继续站在别人的肩膀上

转载, 单独把这部分拿出来 方便以后查找.

生产者-消费者的协程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def consumer():
status = True
while True:
n = yield status
print("我拿到了{}!".format(n))
if n == 3:
status = False

def producer(consumer):
n = 5
while n > 0:
# yield给主程序返回消费者的状态
yield consumer.send(n)
n -= 1

if __name__ == '__main__':
c = consumer()
c.send(None)
p = producer(c)
for status in p:
if status == False:
print("我只要3,4,5就行啦")
break
print("程序结束")
1
2
3
4
5
我拿到了5!
我拿到了4!
我拿到了3!
我只要3,4,5就行啦
程序结束

上面这个例子是典型的生产者-消费者问题,我们用协程的方式来实现它。首先从主程序中开始看,第一句 c = consumer (),因为 consumer 函数中存在 yield 语句,python 会把它当成一个 generator(生成器,注意:生成器和协程的概念区别很大,千万别混淆了两者),因此在运行这条语句后,python 并不会像执行函数一样,而是返回了一个 generator object。

再看第二条语句 c.send (None),这条语句的作用是将 consumer(即变量 c,它是一个 generator)中的语句推进到第一个 yield 语句出现的位置,那么在例子中,consumer 中的 status = True 和 while True: 都已经被执行了,程序停留在 n = yield status 的位置(注意:此时这条语句还没有被执行),上面说的 send (None) 语句十分重要,如果漏写这一句,那么程序直接报错,这个 send () 方法看上去似乎挺神奇,等下再讲它的作用。

下面第三句 p = producer (c),这里则像上面一样定义了 producer 的生成器,注意的是这里我们传入了消费者的生成器,来让 producer 跟 consumer 通信。

第四句 for status in p:,这条语句会循环地运行 producer 和获取它 yield 回来的状态。

好了,进入正题,现在我们要让生产者发送 1,2,3,4,5 给消费者,消费者接受数字,返回状态给生产者,而我们的消费者只需要 3,4,5 就行了,当数字等于 3 时,会返回一个错误的状态。最终我们需要由主程序来监控生产者-消费者的过程状态,调度结束程序。

现在程序流进入了 producer 里面,我们直接看 yield consumer.send (n),生产者调用了消费者的 send () 方法,把 n 发送给 consumer(即 c),在 consumer 中的 n = yield status,n 拿到的是消费者发送的数字,同时,consumer 用 yield 的方式把状态(status)返回给消费者,注意:这时 producer(即消费者)的 consumer.send () 调用返回的就是 consumer 中 yield 的 status!消费者马上将 status 返回给调度它的主程序,主程序获取状态,判断是否错误,若错误,则终止循环,结束程序。上面看起来有点绕,其实这里面 generator.send (n) 的作用是:把 n 发送 generator (生成器) 中 yield 的赋值语句中,同时返回 generator 中 yield 的变量(结果)。

于是程序便一直运作,直至 consumer 中获取的 n 的值变为 3!此时 consumer 把 status 变为 False,最后返回到主程序,主程序中断循环,程序结束。