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

歡迎訪問 生活随笔!

生活随笔

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

python

Python的gevent协程及协程概念

發布時間:2023/12/9 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python的gevent协程及协程概念 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

https://www.cnblogs.com/tkqasn/p/5705338.html

何為協程

協程,又稱微線程。英文名Coroutine。

協程最大的優勢就是協程極高的執行效率。因為子程序切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。

第二大優勢就是不需要多線程的鎖機制,因為只有一個線程,也不存在同時寫變量沖突,在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多。

因為協程是一個線程執行,那怎么利用多核CPU呢?最簡單的方法是多進程+協程,既充分利用多核,又充分發揮協程的高效率,可獲得極高的性能。后續會就這一塊單獨開寫一篇協程+多進程的測試文章。

Python對協程的支持還非常有限,用在generator中的yield可以一定程度上實現協程。雖然支持不完全,但已經可以發揮相當大的威力了。

使用生成器的例子

傳統的生產者-消費者模型是一個線程寫消息,一個線程取消息,通過鎖機制控制隊列和等待,但一不小心就可能死鎖。

如果改用協程,生產者生產消息后,直接通過yield跳轉到消費者開始執行,待消費者執行完畢后,切換回生產者繼續生產,效率極高:

import timedef consumer():r = ''while True:n = yield rif not n:returnprint('[CONSUMER] Consuming %s...' % n)time.sleep(1)r = '200 OK'def produce(c):c.next()n = 0while n < 5:n = n + 1print('[PRODUCER] Producing %s...' % n)r = c.send(n)print('[PRODUCER] Consumer return: %s' % r)c.close()if __name__=='__main__':c = consumer()produce(c)

運行結果

[PRODUCER] Producing 1... [CONSUMER] Consuming 1... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 2... [CONSUMER] Consuming 2... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 3... [CONSUMER] Consuming 3... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 4... [CONSUMER] Consuming 4... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 5... [CONSUMER] Consuming 5... [PRODUCER] Consumer return: 200 OK

注意到consumer函數是一個generator(生成器),把一個consumer傳入produce后:

  • 首先調用c.next()啟動生成器;

  • 然后,一旦生產了東西,通過c.send(n)切換到consumer執行;

  • consumer通過yield拿到消息,處理,又通過yield把結果傳回;

  • produce拿到consumer處理的結果,繼續生產下一條消息;

  • produce決定不生產了,通過c.close()關閉consumer,整個過程結束。

  • 整個流程無鎖,由一個線程執行,produce和consumer協作完成任務,所以稱為“協程”,而非線程的搶占式多任務。

    使用gevent模塊

    Python通過yield提供了對協程的基本支持,但是不完全。而第三方的gevent為Python提供了比較完善的協程支持。

    gevent是第三方庫,通過greenlet實現協程,其基本思想是:

    當一個greenlet遇到IO操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。由于IO操作非常耗時,經常使程序處于等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在運行,而不是等待IO。

    由于切換是在IO操作時自動完成,所以gevent需要修改Python自帶的一些標準庫,這一過程在啟動時通過monkey patch完成:

    import geventdef f(n):for i in range(n):print gevent.getcurrent(), ig1 = gevent.spawn(f, 5) g2 = gevent.spawn(f, 5) g3 = gevent.spawn(f, 5) g1.join() g2.join() g3.join() <Greenlet at 0x10e49f550: f(5)> 0 <Greenlet at 0x10e49f550: f(5)> 1 <Greenlet at 0x10e49f550: f(5)> 2 <Greenlet at 0x10e49f550: f(5)> 3 <Greenlet at 0x10e49f550: f(5)> 4 <Greenlet at 0x10e49f910: f(5)> 0 <Greenlet at 0x10e49f910: f(5)> 1 <Greenlet at 0x10e49f910: f(5)> 2 <Greenlet at 0x10e49f910: f(5)> 3 <Greenlet at 0x10e49f910: f(5)> 4 <Greenlet at 0x10e49f4b0: f(5)> 0 <Greenlet at 0x10e49f4b0: f(5)> 1 <Greenlet at 0x10e49f4b0: f(5)> 2 <Greenlet at 0x10e49f4b0: f(5)> 3 <Greenlet at 0x10e49f4b0: f(5)> 4

    可以看到,3個greenlet是依次運行而不是交替運行。

    要讓greenlet交替運行,可以通過gevent.sleep()交出控制權:

    import gevent import randomdef f(n):for i in range(n):print gevent.getcurrent(), igevent.sleep(random.randint(0,4))g1 = gevent.spawn(f, 3) g2 = gevent.spawn(f, 3) g3 = gevent.spawn(f, 3) g1.join() g2.join() g3.join() 

    運行結果

    <Greenlet at 0x2682c48L: func(3)> 0 <Greenlet at 0x2682e48L: func(3)> 0 <Greenlet at 0x29d9548L: func(3)> 0 <Greenlet at 0x2682c48L: func(3)> 1 <Greenlet at 0x29d9548L: func(3)> 1 <Greenlet at 0x29d9548L: func(3)> 2 <Greenlet at 0x2682c48L: func(3)> 2 <Greenlet at 0x2682e48L: func(3)> 1 <Greenlet at 0x2682e48L: func(3)> 2

    3個greenlet交替運行,

    把循環次數改為500000,讓它們的運行時間長一點,然后在操作系統的進程管理器中看,線程數只有1個。

    當然,實際代碼里,我們不會用gevent.sleep()去切換協程,而是在執行到IO操作時,gevent自動切換,代碼如下:

    from gevent import monkey; monkey.patch_all()#有IO才做時需要這一句 import gevent import urllib2def f(url):print('GET: %s' % url)resp = urllib2.urlopen(url)data = resp.read()print('%d bytes received from %s.' % (len(data), url))gevent.joinall([gevent.spawn(f, 'https://www.python.org/'),gevent.spawn(f, 'https://www.yahoo.com/'),gevent.spawn(f, 'https://github.com/'), ])  GET: https://www.python.org/ GET: https://www.yahoo.com/ GET: https://github.com/ 45661 bytes received from https://www.python.org/. 14823 bytes received from https://github.com/. 304034 bytes received from https://www.yahoo.com/.

    從結果看,3個網絡操作是并發執行的,而且結束順序不同,但只有一個線程。

    小結

    使用gevent,可以獲得極高的并發性能,但gevent只能在Unix/Linux下運行,在Windows下不保證正常安裝和運行,在windows下需要安裝第三方編譯好的包,或者自行編譯。

    總結

    以上是生活随笔為你收集整理的Python的gevent协程及协程概念的全部內容,希望文章能夠幫你解決所遇到的問題。

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