日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python Gevent – 高性能的Python并发框架

發布時間:2025/6/15 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python Gevent – 高性能的Python并发框架 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

話說gevent也沒個logo啥的,于是就擺了這張圖= =|||,首先這是一種叫做greenlet的鳥,而在python里,按照官方解釋greenlet是輕量級的并行編程,而gevent呢,就是利用greenlet實現的基于協程的python的網絡library,好了,關系理清了。。。

話說pycon沒有白去阿,了解了很多以前不知道的東西,比如說協程,gevent,greenlet,eventlet。說說協程,進程和線程大家平時了解的都比較多,而協程算是一種輕量級進程,但又不能叫進程,因為操作系統并不知道它的存在。什么意思呢,就是說,協程像是一種在程序級別來模擬系統級別的進程,由于是單進程,并且少了上下文切換,于是相對來說系統消耗很少,而且網上的各種測試也表明,協程確實擁有驚人的速度。并且在實現過程中,協程可以用以前同步思路的寫法,而運行起來確是異步的,也確實很有意思。話說有一種說法就是說進化歷程是多進程->多線程->異步->協程,暫且不論說的對不對,單從諸多贊譽來看,協程還是有必要理解一下的。

比較慚愧,greenlet沒怎么看就直接看gevent,官方文檔還是可以看看的,尤其是源碼里的examples都相當不錯,有助于理解gevent的使用。

gevent封裝了很多很方便的接口,其中一個就是monkey

  • from?gevent?import?monkey
  • monkey.patch_all()
  • 這樣兩行,就可以使用python以前的socket之類的,因為gevent已經給你自動轉化了,真是超級方便阿。

    而且安裝gevent也是很方便,首先安裝依賴libevent和greenlet,再利用pypi安裝即可

  • sudo apt-get install libevent-dev
  • sudo apt-get install python-dev
  • sudo easy-install gevent
  • 然后,gevent中的event,有wait,set等api,方便你可以讓某些協程在某些地方等待條件,然后用另一個去喚醒他們。

    再就是gevent實現了wsgi可以很方便的當作python的web server服務器使。

    最后放送一個我利用gevent實現的一個帶有緩存的dns server

  • # -*- coding: UTF-8 -*-
  • import?gevent
  • import?dnslib
  • from?gevent?import?socket
  • from?gevent?import?event
  • rev=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
  • rev.bind(('',53))
  • ip=[]
  • cur=0
  • def?preload():
  • for?i?in?open('ip'):
  • ip.append(i)
  • print?"load "+str(len(ip))+" ip"
  • def?send_request(data):
  • global?cur
  • ret=rev.sendto(data,(ip[cur],53))
  • cur=(cur+1)%len(ip)
  • class?Cache:
  • def?__init__(self):
  • self.c={}
  • def?get(self,key):
  • return?self.c.get(key,None)
  • def?set(self,key,value):
  • self.c[key]=value
  • def?remove(self,key):
  • self.c.pop(key,None)
  • cache=Cache()
  • def?handle_request(s,data,addr):
  • req=dnslib.DNSRecord.parse(data)
  • qname=str(req.q.qname)
  • qid=req.header.id
  • ret=cache.get(qname)
  • if?ret:
  • ret=dnslib.DNSRecord.parse(ret)
  • ret.header.id=qid;
  • s.sendto(ret.pack(),addr)
  • else:
  • e=event.Event()
  • cache.set(qname+"e",e)
  • send_request(data)
  • e.wait(60)
  • tmp=cache.get(qname)
  • if?tmp:
  • tmp=dnslib.DNSRecord.parse(tmp)
  • tmp.header.id=qid;
  • s.sendto(tmp.pack(),addr)
  • def?handle_response(data):
  • req=dnslib.DNSRecord.parse(data)
  • qname=str(req.q.qname)
  • print?qname
  • cache.set(qname,data)
  • e=cache.get(qname+"e")
  • cache.remove(qname+"e")
  • if?e:
  • e.set()
  • e.clear()
  • def?handler(s,data,addr):
  • req=dnslib.DNSRecord.parse(data)
  • if?req.header.qr:
  • handle_response(data)
  • else:handle_request(s,data,addr)
  • def?main():
  • preload()
  • while?True:
  • data,addr=rev.recvfrom(8192)
  • gevent.spawn(handler,rev,data,addr)
  • if?__name__ ==?'__main__':
  • main()
  • 這個是直接利用了dict來作為緩存查詢了,在這里還有我將dict換成redis持久化實現的另一個版本(話說redis的python api也可以利用pypi安裝,pypi(PyPI?- the Python Package Index : Python Package Index)這真是個好東西阿),話說可以將這段代碼放到國外的服務器上去運行,然后修改dns的地址去指向它,然后你懂的。。。

    ##################################

    gevent相關,請去官網http://pypi.python.org/pypi/gevent#downloads下載gevent模塊

    程序及注釋如下:

    # -*- coding: cp936 -*-
    import gevent?
    import time

    from gevent import event #調用gevent的event子模塊

    #三個進程需要定義三個事件event1,event2,event3,來進行12,23,31循環機制,即進程一,進程二,進程三順序執行
    def fun1(num,event1,event2):#固定格式
    ??? i=0
    ??? while i<10: #設置循環10次
    ??????? i+=1
    ??????? time.sleep(1) #睡眠1秒
    ??????? print'進程一:111111111'
    ??????? event2.set() #將event2值設為True
    ??????? event1.clear()#將event1值設為False
    ??????? event1.wait()#event1等待,其值為True時才執行
    ????????
    def fun2(num,event2,event3):
    ??? i=0
    ??? while i<10:
    ??????? i+=1
    ??????? time.sleep(1)
    ??????? print'進程二:222222222'
    ??????? event3.set()#將event3值設為True
    ??????? event2.clear()#將event2值設為False
    ??????? event2.wait()#event2等待,其值為True時才執行

    def fun3(num,event3,event1):
    ??? i=0
    ??? while i<10:
    ??????? i+=1
    ??????? time.sleep(1)
    ??????? print'進程三:333333333'
    ??????? event1.set()
    ??????? event3.clear()
    ??????? event3.wait()

    if __name__=="__main__": #執行調用格式
    ??? act1=gevent.event.Event() #調用event中的Event類,用act1表示
    ??? act2=gevent.event.Event()?
    ??? act3=gevent.event.Event()
    ??? #三個進程,act1,act2,act3
    ??? Gevents=[] #建立一個數列,用來存和管理進程
    ??? g=gevent.Greenlet(fun1,1,act1,act2) #調用gevent中的Greenlet子模塊,用Greenlet創建進程一
    ??? g.start()?
    ??? print'進程一啟動:'
    ??? Gevents.append(g) #將進程一加入到Gevents數列

    ??? g=gevent.Greenlet(fun2,2,act2,act3)
    ??? g.start()
    ??? print'進程二啟動:'
    ??? Gevents.append(g)

    ??? g=gevent.Greenlet(fun3,3,act3,act1)
    ??? g.start()
    ??? print'進程三啟動:'
    ??? print'所有進程都已啟動!'
    ??? Gevents.append(g)

    ??? gevent.joinall(Gevents) #調用Greenlet中的joinall函數,將Gevents的進程收集排列

    ##################################

    看看Gevent。
    您可以創建幾個 Greenlet 對象為幾個任務。
    每個 greenlet 是綠色的線程。

    from gevent import monkey monkey.patch_all() import gevent from gevent import Greenletclass Task(Greenlet):def __init__(self, name):Greenlet.__init__(self)self.name = name def _run(self):print "Task %s: some task..." % self.namet1 = Task("task1") t2 = Task("task2") t1.start() t2.start() # here we are waiting all tasks gevent.joinall([t1,t2])

    ##################################

    關于gevent

    首先,gevent是一個網絡庫:libevent是一個事件分發引擎,greenlet提供了輕量級線程的支持。所以它不適合處理有長時間阻塞IO的情況。

    gevent就是基于這兩個東西的一個專門處理網絡邏輯的并行庫。

    ?

    1. gevent.spawn啟動的所有協程,都是運行在同一個線程之中,所以協程不能跨線程同步數據。

    ?

    2. gevent.queue.Queue 是協程安全的。

    ?

    3. gevent啟動的并發協程,具體到task function,不能有長時間阻塞的IO操作。因為gevent的協程的特點是,當前協程阻塞了才會切換到別的協程。

    如果當前協程長時間阻塞,則不能顯示(gevent.sleep(0),或隱式,由gevent來做)切換到別的協程。導致程序出問題。

    ?

    4. 如果有長時間阻塞的IO操作,還是用傳統的線程模型比較好。

    ?

    5. 因為gevent的特點總結是:事件驅動+協程+非阻塞IO,事件驅動值得是libvent對epool的封裝,來基于事件的方式處理IO。

    協程指的是greenlet,非阻塞IO指的是gevent已經patch過的各種庫,例如socket和select等等。

    ?

    6. 使用gevent的協程,最好要用gevent自身的非阻塞的庫。如httplib, socket, select等等。

    ?

    7. gevent適合處理大量無阻塞的任務,如果有實在不能把阻塞的部分變為非阻塞再交給gevent處理,就把阻塞的部分改為異步吧。

    ##################################

    gevent注意事項

    1. gevent.server.StreamServer 會針對每個客戶端連接啟動一個greenlet處理,要注意的是,如果不循環監聽( 阻塞在read ),

    每個greenlet會在完成后立即退出,從而導致客戶端退出( 發送FIN_ACK給客戶端 )。這個問題折騰了一晚上,終于弄明白了。坑爹啊。。。

    ?

    2. 要非常仔細的檢查,greenlet處理的代碼,發現有可能阻塞IO的地方,盡量用gevent提供的庫。

    ?

    3. 一些第三方庫隱藏了自己的實現( 通常是直接封裝C庫),要使得gevent兼容它們,可以用monkey_patch,但不保證全部管用。

    ?

    4. 最后最后的一點,gevent的greenlet性能非常高,所以如果是用它作為并發的client端,那么一定要注意,你的server端處理速度一定要足夠快!

    否則你的客戶端代碼會因為服務端的慢速,而失去了greenlet的優勢。。。

    ####################################

    安裝 libevent:apt-get install libevent-dev

    安裝python-dev:apt-get install python-dev

    安裝greenlet:easy_install greenlet

    安裝gevent:easy_install gevent

    一個小測試,測試gevent 的任務池

    [python]?view plain?copy
  • from?gevent?import?pool??
  • g?=?pool.Pool()??
  • def?a():??
  • ????for?i?in?xrange(100):??
  • ????????g.spawn(b)??
  • def?b():??
  • ????print?'b'??
  • g.spawn(a)??
  • g.join()??

  • 以上內容轉自互聯網:http://www.coder4.com/archives/1522

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的python Gevent – 高性能的Python并发框架的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。