关于协程的理解

参考文档:http://www.cnblogs.com/coderzh/articles/1202040.html(我觉得这个作者讲的很好,让我茅塞顿开,所以借鉴了不少,如有侵权嫌疑请私戳哦)

                  廖雪峰python官方文档

1、浅层

def h():
    print('Wen Chuan')
    yield 5
    print('Fighting!')

c = h()
next(c)

  输出:

       这里的第一个next,只输出了yield之前的东西。

       程序从c=h()开始,然后进入next语句,然后启动generator h(),打印第一句"Wen chuan",然后进入yield,往generator生成一个数据5,然后也没有退出generator之类的语句,所以卡在这了,如果在来一个next,则可以全部输出:

      为啥没有输出5?当我们再次调用next时,会继续执行,直到找到下一个yield表达式。由于后面没有yield了,因此会拋出异常。从上面这个例子也可验证next等价于send(None)这个道理。

2、深入

 1 def h():
 2     print('Wen Chuan')
 3     mm = yield 5  # Fighting!
 4     print("mm=",m)
 5     dd = yield 12
 6     print('We are together!   dd=',dd)
 7 
 8 c = h()
 9 m=next(c)  #相当于c.send(None)
10 d=c.send('Fighting!')  #(yield 5)表达式被赋予了'Fighting!'
11 print(m,d)
12 a=next(c)
13 print('error',a)

       过程:

       1.c=h(),程序开始

       2.m=next(c)启动生成器

       3.进入生成器h(),一直扫描直到遇到yield,所以打印了‘Wen chuan’,此时遇到yield 5,将5压进生成器,因为第三行代码yield在等式右边,所以返回generator的参数,也就是5,赋值给mm(这里我总是弄混到底mm是甚麽),此时“子程序”停留在第三行

       4.回到“主程序”第9行,因为将next获得的值赋给m,所以此时刚才进栈的5再出栈给m,接着运行第10行(send作用和next相似,但是send可以传递yield表达式的值,如果h()是需要传参的,就用send传)因为是send,所以又去“子程序”运行,原本“子程序”运行到第三行,将send携带的参数传递给等式左边,即mm=Fighting!,接着第四行打印mm,接着运行,遇到yield 12,将12压进栈,此时“子程序”停留在第5行等式右边

       5.回到“主程序”第10行,send从生成器出栈12复制给d,接着运行11行打印5,12,然后12行next又去“子程序”找yield,回到子程序第5行,因为next不能带参数,所以这个yield表达式没有值,所以dd=None,然后打印第6行,然后h()已经运行完毕,没有找到yield,报错,然后就不会返回到“主程序了”,接下来的13行也没有打印。

3、理解

1)

 1 def h():
 2     print('Wen Chuan')
 3     mm = yield 5  # Fighting!
 4     print("mm=",m)
 5     dd = yield 12
 6     print('We are together!   dd=',dd)
 7 
 8 c = h()
 9 m=next(c)  #相当于c.send(None)
10 d=c.send('Fighting!')  #(yield 5)表达式被赋予了'Fighting!'
11 print(m,d)
12 13 print('error')

        这里,没有报错,而且执行了13行没有执行第6行:在第10行send之后执行到“子程序”中的第5行,就不往下执行了,然后返回到第10行,接着把“主程序”执行完。而上一个例子报错是又有一个next,所以“子程序”接着往下找把“子程序”找完了也没找到yield,所以第6行执行了,而13行不执行,相当于在“主程序”中第12行遇到一个error直接退出本层循环所以退出运行,所以第13行就没有执行。

2)

        这里类似“主程序”“子程序”或者多线程的理解来理解协程,但是协程与多线程相比不需要线程切换的开销,与子程序比起来协程可以“子程序”内部中断,再去执行别的“子程序”,有点类似CPU中断。

        上面还有一个问题是为甚麽没有输出yield的5,通过第二个例子的理解,也可看到,第一个例子只有next语句,并不是b=next(c),所以是有返回值5的,只是没有接收。在这里要特别注意b=yield 5,b到底是多少,b的值是send传进来的,而5这个值又被传回给bb=send中的bb。

3)

         有点全局变量和局部变量的感觉,可以在“子程序”中调用“主程序”的m,但是在“主程序”中不能调用“子程序”的mm,我的理解是h()是一个generator,只有通过yield的数据才能放在这个generator中,同样,要调用的数据也必须是yield过的,这里的mm并不是yield的数据,所以在“主程序”中显示没有这个mm变量

 1 def h():
 2     print('Wen Chuan')
 3     mm = yield 5  
 4     print("mm=",m,mm)#可以调用m
 5     dd = yield 12
 6     print('We are together!   dd=',dd)
 7 
 8 c = h()
 9 m=next(c)  
10 d=c.send('Fighting!')  
11 print(m,d)
12 
13 print('error',mm)#不能调用mm

4、关于廖老师网站那个题目的运行过程的理解

 1 def consumer():
 2     r = ''
 3     index=1
 4     while True:
 5         n = yield r
 6         if not n:
 7             return
 8         print('[CONSUMER] Consuming %s...<index=%s>' % (n,index))
 9         r = '200 OK'
10         index+=2
11 
12 def produce(c):
13     c.send(None)
14     n = 0
15     while n < 5:
16         n = n + 1
17         print('[PRODUCER] Producing %s...' % n)
18         r = c.send(n)
19         print('[PRODUCER] Consumer return: %s' % r)
20     c.close()
21 
22 c = consumer()
23 produce(c)

 

         1.第22行开始运行程序,第23行produce(c),进入produce函数

         2.进入produce函数,第13行预激generator,进入consumer函数,直到运行到第5行,此时consumer中的这个n值还没有被赋值,yield栈中为‘ ’,再返回produce函数第13行,因为无赋值,接着进入后面

         3.第17行输出Producing 1...,然后第18行将produce的n=1传给consumer,跳转到第5行,将1赋值给consumer中的这个n,接着往下执行,打印Consuming 2...,然后r='200 ok',再进入while true,运行到第5行,此时将r='200 ok'yield进栈,返回到produce函数

         4.返回到produce函数第18行,send取出当前栈中的‘200 ok’赋值给produce这里的r,然后打印Consumeing return :200 ok,然后进入while n<5:接下来循环进行。

         5.直到最后一次,consumer此时在第5行,yield进栈‘200 ok',此时n还没赋值,返回produce函数第18行,然后打印Consumeing return :200 ok,然后退出while n<5循环,然后这里不知道是怎末退出consumer的,从consumer来说,接下来因为第5行没有收到新的数据,所以这里的n值为None,通过if not n可以退出,然后返回到produce第20行,手动关闭生生成器,退出整个程序。然鹅我删掉了close()和if not n,还是可以正常退出。还等学习更多相关知识应该可以彻彻底底的理解协程整个过程吧!

         额外:这里设了一个index可以看到每次produce和consumer互相转换的时候,这个index不受影响,但是在consumer以外的环境调用不了index,这一点比起局部变量来说要舒服多了。

猜你喜欢

转载自www.cnblogs.com/rainbowdawn/p/10674476.html