刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程。
引用官方的说法:
与线程相比,协程更轻量。一个python线程大概占用8M内存,而一个协程只占用1KB不到内存。协程更适用于IO密集型的应用。
当然在讲协程的实现之前,有必要先来看一下send方法。
send方法
yield表达式有一个返回值,send方法的作用就是控制这个返回值,send的参数就是yield表达式的返回值。我们来看一下官方文档上关于send的定义:
举个栗子:
上面的代码输出:
第一次调用next的时候,程序从函数最开始处运行,打印出
before yield
执行到yield处,停在该处。
接下来,向生成器send(1) 。send在这里起到两个作用,一个是将参数赋给yield的返回值,然后该返回值赋给了变量x;一个是继续程序的执行,直到下一次遇到yield停下来,第二个功能和next相似。其实,next就相当于send(None)。
之心了send(1)后,x被赋值给yield的返回值,即send的参数1,并继续往下执行,打印出了
after yield:1
继续执行,回到循环的开始,向下执行,打印出
before yield
再次遇到yield,停在该处,等待下一次send 或者next的调用。
向生成器send(2)。这里的步骤和send(1)相同,打印出下面两条后,在yield处停住。
after yield:2
before yield
执行next(g),x被赋值为yield表达式的返回值,也就是None,继续向下执行,打印出
after yield:None
再次回到循环的开始,向下执行,打印出
before yield
程序运行结束
现在是不是有点理解send了?
yield和send实现python协程
我们用协程实现一个生产者、消费者的例子:
运行上面的程序,会输出:
produce函数负责生产数据,consume函数负责消费数据。具体执行过程如下:
1 首先调用consume函数。consume函数的返回是一个生成器,把这个生成器传入produce函数。
2 produce函数中调用next(c)启动生成器。
3 计算n = n + 1生成数据,一旦生产了数据,调用c.send(n) 切换到consume执行。
4 consume函数中拿到数据后赋值给n,继续执行yield后面的语句
5 consume函数中打印消费的数据,并设置返回值r,又回到循环的开始,通过yield把结果传回。
6 produce拿到consume返回的值,继续生产下一个数据。
7 5个数据生产完毕后,循环结束,通过c.close() 关闭consume,结束全过程
produce和consume函数在一个线程内执行,通过调用send方法和yield互相切换,实现协程的功能