Python协程(generator, yield, send)
Python对协程的支持是通过generator生成器实现的。在generator中,不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。
def foo(): print("starting...") while True: res = yield 4 print("res:",res) g = foo() print(next(g)) print("*"*20) print(next(g))
执行过程
1.程序开始执行以后,因为foo函数中有yield关键字,所以foo函数并不会真的执行,而是先得到一个生成器g(相当于一个对象)
2.直到调用next方法,foo函数正式开始执行,先执行foo函数中的print方法,然后进入while循环
3.程序遇到yield关键字,然后把yield想成return,return了一个4之后,程序停止,并没有执行赋值给res操作,此时next(g)语句执行完成,所以输出的前两行(第一个是while上面的print的结果,第二个是return出的结果)是执行print(next(g))的结果
4.程序执行print(“*”*20),输出20个*
5.又开始执行下面的print(next(g),这个时候和上面那个差不多,不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,也就是要执行res的赋值操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数),所以这个时候res赋值是None,所以接着下面的输出就是res:None
6.程序会继续在while里执行,又一次碰到yield,这个时候同样return出4,然后程序停止,print函数输出的4就是这次return出的4。
yield简单实现协程
import time def A(): while True: print('----A----') yield time.sleep(0.5) def B(c): while True: print('----B----') c.__next__() time.sleep(0.5) if __name__ == '__main__': a = A() B(a)
yield中send函数的使用
send()发送数据
send 是发送一个参数给 res 的, 因为上面讲到, return 的时候, 并没有把 4 赋值给 res,下次执行的时候只好继续执行赋值操作, 只好赋值为 None 了, 而如果用 send 的话, 开始执行的时候, 先接着上一次(return 4 之后) 执行, 先把 10 赋值给了 res,然后执行 next 的作用,遇见下一回的 yield, return 出结果后结束
def foo(): print("starting...") while True: res = yield 4 print("res:",res) g = foo() print(next(g)) print("*"*20) print(g.send(10))
协程实现生产者消费者
import time #生产者 def produce(c): c.send(None) for i in range(1,6): print('生产者生产%d 产品'%i) c.send(str(i)) time.sleep(1) #消费者 def customer(): res = '' while True: data = yield res if not data: return print('消费者消费%s产品'%data) if __name__ == '__main__': c = customer() produce(c)