关键字 协程 生成器 yield
先来看一个简单例子
输出结果
接下来一步步拆分理解
打断点调试看看
可以看出,第8行的c是一个generator,即生成器
然后再看一个关于生成器的简单例子
可以看出,每调用一次g.next(),就计算一个元素的结果,直到计算到最后一个元素;没有更多的元素时,就抛出StopIteration的错误。
在Python中,这种一边循环一边计算的机制,就称为生成器(Generator)。
generator是可迭代对象,所以可以用for循环迭代
回到图1-1第4行,为了避免抛出StopIteration的错误,所以这里用了while True,让func()函数一直处于循环。
那么,图1-2的输出结果是怎么得到的呢?原因就在图2-1第9~11行这三行里。这是python协程的重点,需要理解的有:yield、生成器的send()和next()函数。
如果一个函数中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
generator的next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。
所以图2-1的第9行改成m = c.send(None),效果是一样的。
有了上面这些关于生成器的知识点做铺垫,再来理解图1-2的输出结果就比较容易了。
m= c.next()
这条语句,是首次调用,用来启动c这个生成器,同时调用func()函数,进入while第1次循环,遇到yield,函数中断。
n1 = c.send("Hello")
这条语句,从上面第1次循环的中断处开始执行,yield接收c.send("Hello")的参数"Hello",并把"Hello"赋值给a,所以输出结果为Hello,第1次循环结束。开始while第2次循环,在第5行又遇到yield,函数中断。
n2= c.send("World")
这条语句,从上面第2次循环的中断处开始执行,yield接收c.send("World")的参数"World",并把"World"赋值给a,所以这条语句输出结果World,第2次循环结束。开始while第3次循环,在第5行又遇到yield,函数中断。
协程的一般应用是:有两个或者多个函数,这里假设有两个函数A和B,在执行A的过程中,可以随时中断,去执行B,B也可能在执行过程中中断再去接着执行A。如下:
输出结果:
有了上面2个例子,现在来看看协程的概念。
协程,又称微线程,纤程。
线程是系统级别的,它们是由操作系统调度;协程是程序级别的,由程序员根据需要自己调度。我们把一个线程(图4-1所示的脚本)中的一个个函数(A和B)叫做子程序,那么子程序(A)在执行过程中可以中断去执行别的子程序(B);别的子程序(B)也可以中断回来继续执行之前的子程序(A),这就是协程。