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