greenlet模塊內(nèi)部使用了協(xié)程的概念,在單線程內(nèi),我們需手動調(diào)用switch切換協(xié)程,使用方法如下
from greenlet import greenlet
def eat(name):
print('%s eat 1' %name)
g2.switch('egon')
print('%s eat 2' %name)
g2.switch()
def play(name):
print('%s play 1' %name)
g1.switch()
print('%s play 2' %name)
g1=greenlet(eat)
g2=greenlet(play)
g1.switch('egon')#可以在第一次switch時傳入?yún)?shù),以后都不需要
執(zhí)行結(jié)果
egon eat 1
egon play 1
egon eat 2
egon play 2
一個協(xié)程遇到IO操作自動切換到其它協(xié)程(如何實(shí)現(xiàn)檢測IO,yield、greenlet都無法實(shí)現(xiàn),就用到了gevent模塊(select機(jī)制))
安裝:pip3 install gevent
Gevent 是一個第三方庫,可以輕松通過gevent實(shí)現(xiàn)并發(fā)同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴(kuò)展模塊形式接入Python的輕量級協(xié)程。 Greenlet全部運(yùn)行在主程序操作系統(tǒng)進(jìn)程的內(nèi)部,但它們被協(xié)作式地調(diào)度。
g1=gevent.spawn(func,1,2,3,x=4,y=5)創(chuàng)建一個協(xié)程對象g1,spawn括號內(nèi)第一個參數(shù)是函數(shù)名,如eat,后面可以有多個參數(shù),可以是位置實(shí)參或關(guān)鍵字實(shí)參,都是傳給函數(shù)eat的
g2=gevent.spawn(func2)
g1.join() #等待g1結(jié)束
g2.join() #等待g2結(jié)束
#或者上述兩步合作一步:gevent.joinall([g1,g2])
g1.value#拿到func1的返回值
在在gevent中,gevent.sleep(2)模擬的是gevent可以識別的io阻塞,而time.sleep(2)或其他的阻塞,gevent是不能直接識別的需要用下面一行代碼,打補(bǔ)丁,就可以識別了
from gevent import monkey;monkey.patch_all()必須放到被打補(bǔ)丁者的前面,如time,socket模塊之前
from gevent import monkey;monkey.patch_all()
import gevent
import time
def eat():
print('eat food 1')
time.sleep(2) # 會自動的跳轉(zhuǎn)到play
print('eat food 2')
def play():
print('play 1')
time.sleep(1) # 會自動的跳轉(zhuǎn)到eat
print('play 2')
g1=gevent.spawn(eat)
g2=gevent.spawn(play)
gevent.joinall([g1,g2])
print('主')