协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。类似于CPU中的中断,与函数调用不一样。
测试代码:
def consumer(): r = '' print('测试consumer') while True: n = yield r if not n: print('测试c.send方法的运行过程') return print('[CONSUMER] Consuming %s...' % n) r = '200 OK' def produce(c): print('测试生成器的执行过程') c.send(None) n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) print('[PRODUCER] Consumer return: %s' % r) c.close() c = consumer() produce(c)
运行结果:
测试生成器的执行过程 测试consumer [PRODUCER] Producing 1... [CONSUMER] Consuming 1... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 2... [CONSUMER] Consuming 2... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 3... [CONSUMER] Consuming 3... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 4... [CONSUMER] Consuming 4... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 5... [CONSUMER] Consuming 5... [PRODUCER] Consumer return: 200 OK
最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
本代码运行流程:
1.先创建消费者生成器对象,然后执行生产者,在生产者中,执行第一句代码c.send(None)是启动
消费者生成器,开始执行,直到遇到yield停止,这句代码相当于调用next(c),它的作用是起到
“预激”效果,此时的send参数没有传给n。
2.然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
3.consumer通过yield拿到消息,处理,又通过yield把结果传回;
4.produce拿到consumer处理的结果,继续生产下一条消息;
5.produce决定不生产了,通过c.close()关闭consumer,整个过程结束
c.send()函数有1、传值 2、调用next()方法的作用。
参考3有协程与进程线程之间的关系。