python里面的关键字yield,设计初衷应该就是方便处理协程的。
协程(Coroutine),又称微线程,最大的优势就是极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
生成器
生成器不会把结果保存在一个系列中,而是保存生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常结束。
gen = (x**2 for x in range(5))
这里跟就相当于一个生成器。而yield的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator。下面是用yield也就是协程实现的生产者消费者模型
# coding=utf-8
import time
def consumer():
r = ''
while True:
n = yield r
#每一次作为生成器调用consumer时(next()),阻塞在下一行
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
time.sleep(1)
r = '200 OK'
def produce(c):
c.next()
# next(c)
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()
if __name__ == '__main__':
c = consumer()
produce(c)
另一种方式
yield处理函数得到的生成器不能用for i in XXX这样遍历,能用for的,必须是下面这种写法实现的才可以~
class Iter:
def __init__(self):
self.start=-1
def __iter__(self):
return self
def __next__(self):
self.start +=2
return self.start
I = Iter()
for count in range(5):
print(next(I))
总结
- 按照鸭子模型理论,生成器就是一种迭代器,可以使用for进行迭代。
- 第一次执行next(generator)时,会执行完yield语句后程序进行挂起,所有的参数和状态会进行保存。再一次执行next(generator)时,会从挂起的状态开始往后执行。在遇到程序的结尾或者遇到StopIteration时,循环结束。
- 可以通过generator.send(arg)来传入参数,这是协程模型。 可以通过generator.throw(exception)来传入一个异常。-
- throw语句会消耗掉一个yield。可以通过generator.close()来手动关闭生成器。
- next()等价于send(None)