更新:导入一个有monkey.patch_all()的库,应该用函数把它包起来,否则会抛出错误python
- RuntimeError: cannot release un-acquired lock 编程
在《python高性能编程》一书中做者开始讲协程用的就是gevent模块做为例子。先举一个简单的例子:函数
协程极大大提升了性能
若是有100个foo,bar函数,每一个须要阻塞一秒,那么串行执行须要100秒以上,而I/O多路复用执行,在一秒以后100个程序执行完毕。性能
协程提升性能的缘由ui
- 全部的阻塞请求同时发生,只要函数输入到位
- cpu和操做系统的高度配合spa
-能够这么想象 操作系统
1 线程读代码,读到一步须要去取数据,
2 线程本身不取数据,叫操做系统去取,取数据步骤参考途中1,3,4,2
3 操做系统取数据,线程就不读代码了,不干其余事,就在这等着
4 等数据到了,线程继续读代码,按代码干事
线程
-重点来了,IO多路复用以后事情发生了变化:协程
- 线程很快找到查看了代码,发现代码中指出了有一些代码是能够同时执行的
- 好比下图有4处能够同时执行的代码,
对象
-每一处代码里面可能也有阻塞,因为更里面的阻塞还不能发起请求主要先不关注,
- 线程拿起1处的代码,向系统发起请求,不等待,回到代码2处
- 再去操做系统处发送请求,如此反复,直到代码代表的特殊代码块都发起了请求
- 线程毫无停歇,只要操做系统使其获得数据,他就运行代码,并重复以上步骤
- 对比:在串行的状况下,线程在1.1处停下等待0.1s,而IO多路复用已经把活全作完了
协程做用的范围:
- 如下两个条件同时具有
I/O密集型任务。
任务自己结果不受其余任务
如何标记特殊代码块。(猴子补丁+gevent.spawn())
- 打上猴子补丁
from gevent import monkey
monkey.patch_all()
- gevent.spawn(function,*arg,**kwargs)
若是一个function内部没有阻塞,那么到这一步,正常执行
若是function能有阻塞,那么它被冻结并被标记成特殊代码块
- 使用内置方法使其开始执行
gevent.joinall()生成对象是list类型
iwait生成对象是生成器类型
对单个对象使用.join()方法,可是没法经过.value获取函数返回值
对单个对象使用.get()方法,能够直接运行并得到返回值,get(timeout=3)还能设置超时时间
- 无论哪一个方法,生成对象的元素使用.value,获得那些特殊代码块的返回值,
若是没有返回值,那就不用管
信号量(from gevent.lock import BoundedSemaphore)
- 生成计算器对象,并设置值
bigest=BoundedSemaphore(5)
生成最大数为5的计数器
- 在代码中调用
使用with方法
或使用bigest.acquire(), bigest.release()
只能用一次的超时控制(gevent.Timeout):
- 在.join()方法前加上
timeout=Timeout(2)
timeout.start()
- timeout支持with调用,其__enter__()方法调用了start(),不知道在函数内部调用会有什么效果?
还有许多内容,但用好上面这些已能让你代码执行速度快上十倍了。
好吧,再来一点干货:不一样线程内相互控制以及传递值
import gevent from gevent.event import AsyncResult
a = AsyncResult()
a.set('值')
a.get()='值'
解释:a实例化时给全部a.get() 后面的代码加锁,而后a.set()解锁,a.get()获取一个值