对Python协程的一点理解
参照教程利用协程实现的一个很简单的"生产者-消费者"模型如下:
import time
def consumer():
r = ''
count = 0
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
count += 1
print('Consumer count: %s' % count)
time.sleep(5)
r = '200 OK'
def produce(c):
c.send(None)
n = 0
while n < 3:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()
c = consumer()
produce(c)
执行结果如下
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
Consumer count: 1
# wait 5 secs
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
Consumer count: 2
# wait 5 secs
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
Consumer count: 3
# wait 5 secs
[PRODUCER] Consumer return: 200 OK
在这个例子里,consumer
是一个生成器,produce
是被执行的主程序,通过形如generator.send(value)
的方法去调用生成器。生成器的每一次被调用,都会向下执行直到yield
为止。
我们可以看到Comsumer count
每一次的值都不一样,生成器每一次yield
返回值时,虽然程序的执行切回了主程序,但是生成器中的整个环境(局部变量等)都被保存了起来,当下次再被调用时再被复原,就好像生成器接续上次继续执行一样。
关于send函数
官方文档对send
函数的解释如下
Resumes the execution and “sends” a value into the generator function. The value argument becomes the result of the current yield expression. The send() method returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value.
也就是说,send
函数是用来向生成器传值,并且获取生成器yield
的值的。
一般来讲,在正式send值给生成器之前要先send一个空值,这是为了让生成器的代码向下执行,进入While Ture
循环。
n = yield r
这行代码在生成器非第一次被调用的时候,会分两次执行
- 接受
send
函数传入的值 - 继续向下执行,在下一次的循环中执行到这里的时候
yield r
返回r值。