python原生的一点东西【3】

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)

刘摸鱼

退堂鼓表演艺术家

杭州