gevent基于協程的網絡庫,基于libev的快速的事件循環,基于greenlet的輕量級執行單元,重用了Python標準庫中的概念,支持socket、ssl、三方庫通過打猴子補丁的形式來提供同步方式編寫代碼的異步支持,dns解析通過線程池或c-ares,內置的tcp udp http服務器,支持多進程,線程池。
gevent和eventlet
2009年當時eventlet不支持livevent
當時eventlet的monkey-patch有bug導致socket操作會掛起
its Hub API is geared towards pure Python event loops. Making it work smoothly would require significant changes in the interface and implementation of every other hub. The socket module bugs were also specific to event loop, so even though I fixed them for pyevent, they were still present in every other hub.
gevent在libevent的基礎上
當然最新的實現是使用了libev
libevent是事件循環,使用epoll、kqueue,dns是異步的,同時它提供了http服務器。而eventlet則是維持的純python的事件循環(最近才支持epoll)。
除了效率,還集成了信號處理,其他使用libevent的庫也可以集成進來,dns解析也可以異步了,wsgi服務器也是在libevent的自帶服務器上運行的(很快)
和python標準的風格相同
例如線程的事件等都一樣
不同點
沒有eventlet.db_pool
沒有多進程eventlet.processes
如果是在twister的reactor上使用
事件循環
gevent告訴操作系統等數據到達的時候來通知它,然后gevent就可以繼續處理其他的協程,例如已經獲得了數據的。
不像其他的網絡庫,gevent在一個協程中隱式啟動循環,不用調用run或者dispatch什么的,當它要阻塞的時候,就會獲取hub實例并切換到其中,也就是把控制權交給了hub,如果此時還沒有hub就會自動創建一個。
切換規則
注意只有一個greenlet放棄了控制才能執行其他的(調用阻塞函數會切換回hub),這對于io頻繁的系統當然沒問題,但是對于cpu頻繁的系統、或者是調用一些能繞過libev的函數。
鎖、信號量什么的其實沒什么用了,而event、asyncresult、queue等則還是有用的。
使用
創建一個Greenlet然后調用它的start函數,或者直接調用spawn函數。然后在當前協程放棄控制后會切換到并執行。如果greenlet執行時觸發了異常,并不會超出greenlet的界限,只是打印stacktrace 默認是到stderror。
join等待該greenlet退出,kill中斷該greenlet執行,get獲得返回的值或re raise它產生的異常。
可以派生Greenlet,更改它的str方法來改變顯示的traceback信息,但是得在初始化函數中先調用Greenlet.init(self)。
class MyNoopGreenlet(Greenlet):
def __init__(self, seconds):
Greenlet.__init__(self)
self.seconds = seconds
def _run(self):
gevent.sleep(self.seconds)
def __str__(self):
return 'MyNoopGreenlet(%s)' % self.seconds
kill可附帶一個自定義的異常,但是可能該協程會捕獲這個異常,可以附帶timeout參數,也可以直接指定block=False來異步執行。