python gevent

gevent是第三方庫,通過Greenlet提供協程支持(一個Greenlet對象就是一個協程),其基本思想是:
當一個greenlet遇到IO操作時,比如訪問網絡,就會切換執行其它greenlet,等待IO操作完成,再在適當的時候再切換回來繼續執行。由於IO操作非常耗時,通過gevent自動切換greenlet,保證總有一個greenlet在執行,避免空等IO,提高執行效率

1、Greenlet.join(timeout) 函數
與多進程/多線程中join用法基本一致,join函數使當前協程處於wait狀態,直到調用join的協程結束。和多線程不同之處有2點:
(1)主協程若不調用類似join的函數使自己處於wait狀態從而交出控制權,則子協程永遠不會被調度執行(多線程的調度是由系統完成,協程則必須自己主動讓出控制權,其他協程才能被調度執行)。
(2)主協程若不調用join等待子協程執行完退出,主協程執行完後,會自動殺死子協程,而不是等待子協程執行完畢。

2、gevent.monkey
將標準庫中部分阻塞式調用替換爲非阻塞式調用。gevent實現了協程的創建、調度,但每個greenlet內部調用的函數必須是非阻塞式的,如果使用了阻塞式函數,當前協程無法交出控制權實現協程切換。
下面代碼中,time.sleep() 是阻塞式的,協程無法切換,因此協程按照啓動的順序依次執行;gevent.sleep() 是非阻塞式的,協程可以切換,各協程交替執行。

from gevent import monkey; monkey.patch_socket()
import gevent
import time

def f(n):
    for i in range(n):
        print gevent.getcurrent(), i
        time.sleep(0.1)
        # gevent.sleep(0.1)

g1 = gevent.spawn(f, 2)
g2 = gevent.spawn(f, 4)
g3 = gevent.spawn(f, 6)
g1.join()
g2.join()
g3.join()

# out:
<Greenlet at 0x3a05548L: f(2)> 0
<Greenlet at 0x3a05548L: f(2)> 1
<Greenlet at 0x3a05648L: f(4)> 0
<Greenlet at 0x3a05648L: f(4)> 1
<Greenlet at 0x3a05648L: f(4)> 2
<Greenlet at 0x3a05648L: f(4)> 3
<Greenlet at 0x3a05748L: f(6)> 0
<Greenlet at 0x3a05748L: f(6)> 1
<Greenlet at 0x3a05748L: f(6)> 2
<Greenlet at 0x3a05748L: f(6)> 3
<Greenlet at 0x3a05748L: f(6)> 4
<Greenlet at 0x3a05748L: f(6)> 5
from gevent import monkey; monkey.patch_socket()
import gevent
import time

def f(n):
    for i in range(n):
        print gevent.getcurrent(), i
        # time.sleep(0.1)
        gevent.sleep(0.1)

g1 = gevent.spawn(f, 2)
g2 = gevent.spawn(f, 4)
g3 = gevent.spawn(f, 6)
g1.join()
g2.join()
g3.join()

out:
<Greenlet at 0x4085548L: f(2)> 0
<Greenlet at 0x4085648L: f(4)> 0
<Greenlet at 0x4085748L: f(6)> 0
<Greenlet at 0x4085548L: f(2)> 1
<Greenlet at 0x4085648L: f(4)> 1
<Greenlet at 0x4085748L: f(6)> 1
<Greenlet at 0x4085648L: f(4)> 2
<Greenlet at 0x4085748L: f(6)> 2
<Greenlet at 0x4085648L: f(4)> 3
<Greenlet at 0x4085748L: f(6)> 3
<Greenlet at 0x4085748L: f(6)> 4
<Greenlet at 0x4085748L: f(6)> 5

monkey.patch_all() 將monkey實現的非阻塞函數全部完成替換。一般情況下,推薦使用patch_all全部替換,monkey.patch_all()應當儘早執行,最好是程序的第一行,以避免出現不可預期的情況。

3、gevent.pool.Group
通過Group對象,可以管理一組greenlet,當容器中的greenlet任務完成,容器會自動將其刪去。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章