关于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~!
阅读全文
0 0
- 关于Python里面协程的一些理解
- 关于JAVA里面的内部类的一些理解
- 关于python编码的一些理解
- 关于python里面的对齐
- 关于Python 浅拷贝与深拷贝的一些理解
- python里面的一些小知识点
- odoo里面Python的一些简便写法
- 关于java里面注解的理解
- Nodejs里面关于this指向的理解
- android 里面一些关于时间的组件
- Python关于list里面的unicode编码
- 关于python里面的join()函数
- 关于JAXB的一些理解
- 关于bitmap的一些理解
- 关于Hook的一些理解
- 关于JavaBean的一些理解
- 关于异常的一些理解
- 关于内存的一些理解
- Java中的I/O
- java程序员从笨鸟到菜鸟之(二十)常用类Math和System
- 对Linux学习的看法
- Java并发编程:深入剖析ThreadLocal
- 阶层1
- 关于Python里面协程的一些理解
- ChibiOS/RT移植到STM32F407
- Codeforces 770D Draw Brackets! 模拟+中缀表达式
- LeetCode #718 Maximum Length of Repeated Subarray
- 20171104-程序员的自我修养
- C++动态内存管理(比较C动态内存管理)
- android下载解析xml
- GPIO口超强总结
- [bzoj4356][ceoi2014] wall