python模块介绍-gevent介绍:基于协程的网络库
2019獨角獸企業重金招聘Python工程師標準>>>
python模塊介紹-gevent介紹:基于協程的網絡庫 ? ?
介紹
gevent是基于協程的Python網絡庫。特點:
基于libev的快速事件循環(Linux上epoll,FreeBSD上kqueue)。
基于greenlet的輕量級執行單元。
API的概念和Python標準庫一致(如事件,隊列)。
可以配合socket,ssl模塊使用。
能夠使用標準庫和第三方模塊創建標準的阻塞套接字(gevent.monkey)。
默認通過線程池進行DNS查詢,也可通過c-are(通過GEVENT_RESOLVER=ares環境變量開啟)。
TCP/UDP/HTTP服務器
子進程支持(通過gevent.subprocess)
線程池
安裝
gevent目前支持python2.5-2.7,python2.6以前的版本如果要使用ssl還需要安裝ssl模塊。
#?pip?install?gevent實例
下面的示例展示了如何同時運行任務。
>>>?import?gevent>>>?from?gevent?import?socket>>>?urls?=?['www.google.com',?'www.example.com',?'www.python.org']>>>?jobs?=?[gevent.spawn(socket.gethostbyname,?url)?for?url?in?urls]>>>?gevent.joinall(jobs,?timeout=2)>>>?[job.value?for?job?in?jobs]['74.125.128.106',?'93.184.216.119',?'82.94.164.162']job發起之后,gevent.joinall()等待完成,不超過2秒。結果收集在gevent.Greenlet.value屬性。 gevent.socket.gethostbyname()和socket.gethostbyname()的接口一樣,但它并不阻塞解釋器,其他 greenlet繼續暢通無阻的處理請求。
靈猴補丁(Monkey patching)
上面例子使gevent.socket進行socket操作。如果使用標準socket模塊將有3倍耗時,因為DNS請求是串行的。在greenlet中使用標準socket模塊毫無意義,這些模塊和包是怎么建立在socket之上的?
monkey patching這時起作用了,gevent.monkey小心地使用兼容副本替換標準socket模塊的函數和類。這樣,即使是不知道gevent的模塊也受益于greenlet環境運行。
>>>?from?gevent?import?monkey;?monkey.patch_socket()>>>?import?urllib2?#?it's?usable?from?multiple?greenlets?now下面是使用urllib2進行下載的實例:
#!/usr/bin/env?python#?-*-?coding:?utf-8?-*-#?Copyright?(c)?2009?Denis?Bilenko.?See?LICENSE?for?details."""Spawn?multiple?workers?and?wait?for?them?to?complete"""urls?=?['http://www.google.com',?'http://www.yandex.ru',?'http://www.python.org']import?geventfrom?gevent?import?monkey#?patches?stdlib?(including?socket?and?ssl?modules)?to?cooperate?with?other?greenletsmonkey.patch_all()import?urllib2def?print_head(url):print('Starting?%s'?%?url)data?=?urllib2.urlopen(url).read()print('%s:?%s?bytes:?%r'?%?(url,?len(data),?data[:50]))jobs?=?[gevent.spawn(print_head,?url)?for?url?in?urls]gevent.wait(jobs)執行結果:
#?./test.py? Starting?http://www.google.com Starting?http://www.yandex.ru Starting?http://www.python.org http://www.google.com:?11246?bytes:?'<!doctype?html><html?itemscope=""?itemtype="http:/'http://www.python.org:?20471?bytes:?'<!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Trans'http://www.yandex.ru:?208804?bytes:?'<!DOCTYPE?html><html?class="i-ua_js_no?i-ua_css_st'事件循環
不像其他網絡庫,gevent和eventlet類似, 在一個greenlet中隱式開始事件循環。沒有必須調用run()或dispatch()的反應器(reactor),在twisted中是有 reactor的。當gevent的API函數想阻塞時,它獲得Hub實例(執行時間循環的greenlet),并切換過去。如果沒有集線器實例則會動態 創建。
libev提供的事件循環默認使用系統最快輪詢機制,設置LIBEV_FLAGS環境變量可指定輪詢機制。LIBEV_FLAGS=1為select, LIBEV_FLAGS = 2為poll, LIBEV_FLAGS = 4為epoll,LIBEV_FLAGS = 8為kqueue。請閱讀libev文檔了解更多信息http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#FUNCTIONS_CONTROLLING_EVENT_LOOPS。
Libev的API位于gevent.core下。注意libev API的回調在Hub的greenlet運行,因此使用同步greenlet的API。可以使用spawn()和Event.set()等異步API。
多任務合作
所有greenlets都在同一個操作系統線程調度執行。直到特定的greenlet放棄控制,(調用阻塞函數切換到Hub),其他greenlet才有 機會運行。對于I / O密集型應用程序這通常不是問題,但做CPU密集型或者調用封鎖繞過libev事件循環的I/0功能的時會有問題。
一般不需要在greenlet之間同步訪問共享對象, 所以Lock和Semaphore類盡管存在,但是很少使用。從線程和多處理等其他概念仍然常用,如下:
Event:喚醒在調用Event.wait()方法的greenlets。
AsyncResult:和Event類似,但允許傳遞值或異常。隊列和JoinableQueue。
Queu和JoinableQueue.
輕量級偽線程
greenlet通過創建greenlet實例并調用其start方法發起。(spawn()函數就是做這個的快捷方式)。 start方法給greenlet安排一個開關,當前greenlet放棄控制觸發。如果有多個active的事件,將不確定的順序一一執行。
如果在執行過程中出現錯誤,將無法離開greenlet的邊界。未處理的錯誤導致打印堆棧跟蹤及失敗函數和參數:
>>>?gevent.spawn(lambda?:?1/0)>>>?gevent.sleep(1)Traceback?(most?recent?call?last):...ZeroDivisionError:?integer?division?or?modulo?by?zero<Greenlet?at?0x7f2ec3a4e490:?<function?<lambda...>>?failed?with?ZeroDivisionErrortraceback在greenlet退出時同步打印至sys.stderr。
Greenlet實例有如下有用的方法:
join – waits until the greenlet exits;
kill – interrupts greenlet’s execution;
get – returns the value returned by greenlet or re-raised the exception that killed it.
繼承Greenlet類重載其str可以自定義traceback后的字符串。另外還需要重載_run()方法以及在init中調用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可以異步結束Greenlet,浙江將恢復等待的greenlet,不繼續執行而是引發GreenletExit。
>>>?g?=?MyNoopGreenlet(4)>>>?g.start()>>>?g.kill()>>>?g.deadTrueGreenletExit及其子類的處理方式不同于其他異常。GreenletExit不被視為異常狀態,不打印traceback。get可以獲得GreenletExit是GET,就好像它是由greenlet返回,不是raise。
kill方法可以自定義的異常:
>>>?g?=?MyNoopGreenlet.spawn(5)?#?spawn()?creates?a?Greenlet?and?starts?it>>>?g.kill(Exception("A?time?to?kill"))Traceback?(most?recent?call?last):...Exception:?A?time?to?kill MyNoopGreenlet(5)?failed?with?Exceptionkill還可以接受timeout參數指定greenlet退的等待秒數。注意,kill不能保證目標greenlet不會忽視該異常,因此給kill傳遞timeout是個好方法。
超時
gevent的API中的許多函數是同步的,阻塞當前greenlet直到操作完成。例如,kill會等到greenlet結束。多數可以傳遞參數block=False異步執行。
此外,許多同步函數接受超時參數,指定可以阻塞多久(比如:Event.wait(), Greenlet.join(), Greenlet.kill(), AsyncResult?.get()等)。
socket和SSLObject實例也可以超時,由setTimeout方法設置。
如果這些還不夠用,Timeout類可以給任意(yielding)代碼塊增加超時。
了解更多
限制并發可以使用Pool類(參見實例: dns_mass_resolve.py)
gevent自帶的TCP/SSL/HTTP/WSGI服務器。參見實現服務器部分http://www.gevent.org/servers.html。
外部資源
gevent For the Working Python Developer: 是一個更全面的教程。http://sdiehl.github.io/gevent-tutorial/. 中文版本參見http://xlambda.com/gevent-tutorial/
參考資料
gevent主頁: http://www.gevent.org/
gevent英文文檔: http://www.gevent.org/intro.html
gevent程序員指南: http://xlambda.com/gevent-tutorial/
下載地址:https://pypi.python.org/pypi/gevent
作者博客:http://my.oschina.net/u/1433482
Linux slab 分配器剖析
類型:翻譯
轉載于:https://my.oschina.net/u/1433482/blog/192562
總結
以上是生活随笔為你收集整理的python模块介绍-gevent介绍:基于协程的网络库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于java中国象棋游戏
- 下一篇: 我在帝都那几年