关于Python里面协程的一些理解

来源:互联网 发布:ubuntu route设置 编辑:程序博客网 时间:2024/05/29 10:13
#关于Python里面协程的一些理解Python关于协程是有点难理解的,但其实就协程的定义来说其实并不难。协程,又称微线程,纤程。英文名Coroutine协程和多线程以及多进程都不一样,协程有极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。Python对协程的支持是通过生成器(generator)实现的。所谓生成器,也是一种可迭代对象,通常创建生成器有两种方式1、如:g = (x*x for x in range(5))   print(g)=====><generator object <genexpr> at 0x0000000002A3CFC0>   即g是一个生成器对象   操作g有两种方式:①next()方法:next(g)==>0 next(g)==>1 next(g)==>4 next(g)==>9 next(g)==>16②for循环(上面说到了生成器是可以迭代的):for i in g:print(i)输出是:0 1 4 9 162、函数里面包含关键字yield就成了生成器如:def A():for i in range(3):yield i这里值得注意的是它与一般函数执行过程不大一样,遇到yield就返回,它返回的不是具体的值而是一种状态值,然后下一次从yield下面的代码开始执行操作A也是两种,一种next一种for循环。需要注意下下面的代码:>>> def a():...     yield 3...>>> a()<generator object a at 0x0000000002A3CF68>>>> type(a)<class 'function'> 可以看到这里a还是方法>>> type(a())但是a()是生成器<class 'generator'>了解了生成器后便来聊聊协程吧,我们通过一个例子来理解:传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:def consumer():    r = ''    while True:        n = yield r        if not n:            return        print('consumer %s' %n)        r = '886'def produce(c):    c.send(None)    i = 0    while i < 5:        i = i+1        print('produce %s' %i)        m = c.send(i)        print('consumer66660 %s' %m)    c.close()c = consumer()produce(c)输出结果:produce 1consumer 1consumer66660 886produce 2consumer 2consumer66660 886produce 3consumer 3consumer66660 886produce 4consumer 4consumer66660 886produce 5consumer 5consumer66660 886上面这段代码,consumer是一个生成器,而produce函数传入的参数是一个生成器对象。代码的具体执行顺序是最需要弄明白的具体流程:1、首先c = consumer()创建了一个生成器对象c注意这里创建生成器对象c的时候,并没有去执行consumer内部的代码,就比如下面这段代码:>>> def A():...     for i in range(7):...         print(666)...         yield i...>>> n = A()>>> next(n)6660可以看到创建n的时候并没有打印出666,证明没有执行内部代码。2、然后执行produce(c)函数,这里首先执行c.send(None),这个send(None)方法相当于启动了生成器consumer注意这里send(None)参数必须是None,因为send函数是将参数赋值给类似consumer里面的n = yield r 中的n的,而这里根本还没有n存在,你如果传个非空的参数进去就会报错。3、然后转而执行consumer内代码,首先r=‘’,然后进入while循环,执行到n = yield r句的时候我们要特别注意:其实这行代码包含了三个意思:①向函数外抛出(返回)r②暂停,等待next()或send()恢复③赋值,n接收send(m)发送进来的m 这样对应起来,此时执行到这里,向函数外抛出r(这里但是并没有谁去接收这个r)之后,然后函数暂停。4、转而执行produce()里的语句i = 0,然后继续向下执行,到print('produce %s' %i)语句打印出第一条输出:produce 1。5、继续向下执行遇到 m = c.send(i),再次切换到consumer内执行,这里切换过去后要注意,是从n = yield r语句的第③步开始的,即将m = c.send(i)(此时i为1)的i传给了n = yield r里面的n(所以此时n为1)6、继续向下执行consumer里面的代码,if not n 判断条件 not n为false,跳过if语句执行print('consumer %s' %n),输出consumer 1,然后r = ‘886‘,然后继续while循环 又遇到n = yield r,此时抛出的r,然后暂停。 注意:这个抛出的r(已经变为886)被produce内m = c.send(i)的m接受了于是m=’886‘7、然后执行print('consumer66660 %s' %m) 输出:consumer66660 886至此,有了前三行输出:produce 1consumer 1consumer66660 8868、然后进入produce里面第二次while循环,流程跟上面一样,不再赘述。以上,不足之处请多多指教,Thanks~! 

原创粉丝点击