Python
经过yield
提供了对协程的基本支持,可是不彻底。而第三方的gevent
为Python提供了比较完善的协程支持。python
gevent是第三方库,经过greenlet实现协程,其基本思想是:服务器
当一个greenlet遇到IO操做时,好比访问网络,就自动切换到其余的greenlet,等到IO操做完成,再在适当的时候切换回来继续执行。因为IO操做很是耗时,常常使程序处于等待状态,有了gevent为咱们自动切换协程,就保证总有greenlet在运行,而不是等待IO网络
def create_num(all_num): a,b = 0,1 current_num = 0 while current_num < all_num: ret = yield a print(ret) a,b = b, a+b current_num +=1 obj = create_num(10) ret= next(obj) print(ret) ret = obj.send('鲁班七号') print(ret) >>> 0 鲁班七号 1
import time def task1(): while True: print("task one") time.sleep(1) yield def task2(): while True: print("task 2") time.sleep(1) yield def main(): obj1 = task1() obj2 = task2() while True: next(obj1) next(obj2) if __name__ == '__main__': main() >>> task one task 2 task one task 2 task one ......
from greenlet import greenlet import time def f1(): while True: print('-----A-----') gr2.switch() time.sleep(0.5) def f2(): while True: print('-----B-----') gr1.switch() time.sleep(0.5) if __name__ == '__main__': gr1 = greenlet(f1) gr2 = greenlet(f2) gr1.switch()
import gevent import time def f1(n): for i in range(n): print(gevent.getcurrent(),i) gevent.sleep(1) #模拟一个耗时操做,模拟耗时操做要用gevent里面函数 def f2(n): for i in range(n): print(gevent.getcurrent(),i) gevent.sleep(1) if __name__ == '__main__': g1 = gevent.spawn(f1,5) g2 = gevent.spawn(f2,5) g1.join() g2.join() >>> <Greenlet at 0x2f598b0: f1(3)> 0 <Greenlet at 0x2f599c0: f2(3)> 0 <Greenlet at 0x2f598b0: f1(3)> 1 <Greenlet at 0x2f599c0: f2(3)> 1 <Greenlet at 0x2f598b0: f1(3)> 2 <Greenlet at 0x2f599c0: f2(3)> 2
打补丁:不替换sleep, socket.conn,socket.reciv...
等socket
因为切换是在IO操做时自动完成,因此gevent须要修改Python自带的一些标准库,这一过程在启动时经过monkey patch完成函数
from gevent import monkey #打补丁,保证不用替换原来耗时操做的函数 monkey.patch_all()
join_all方法:性能
gevent.joinall([ gevent.spawn(f1, 5), gevent.spawn(f2, 5) ])
#encoding:utf-8 # __author__ = 'donghao' # __time__ = 2019/4/2 13:57 import gevent import time from gevent import monkey #打补丁,保证不用替换原来耗时操做的函数 monkey.patch_all() def f1(n): for i in range(n): print(gevent.getcurrent(),i) time.sleep(1) def f2(n): for i in range(n): print(gevent.getcurrent(),i) time.sleep(1) if __name__ == '__main__': gevent.joinall([ gevent.spawn(f1, 5), gevent.spawn(f2, 5) ]) # 至关于: # g1 = gevent.spawn(f1,5) # g2 = gevent.spawn(f2,5) # g1.join() # g2.join() print('end of main') >>> <Greenlet at 0x39fc2d8: f1(5)> 0 <Greenlet at 0x39fc360: f2(5)> 0 <Greenlet at 0x39fc2d8: f1(5)> 1 <Greenlet at 0x39fc360: f2(5)> 1 <Greenlet at 0x39fc2d8: f1(5)> 2 <Greenlet at 0x39fc360: f2(5)> 2 <Greenlet at 0x39fc2d8: f1(5)> 3 <Greenlet at 0x39fc360: f2(5)> 3 <Greenlet at 0x39fc2d8: f1(5)> 4 <Greenlet at 0x39fc360: f2(5)> 4 end of main
因为gevent是基于IO切换的协程,因此最神奇的是,咱们编写的Web App
代码,不须要引入gevent的包,也不须要改任何代码,仅仅在部署的时候,用一个支持gevent
的WSGI
服务器,马上就得到了数倍的性能提高spa