python中的協(xié)程是通過yield生成器的特性實現(xiàn)的晴圾,但如果直接使用確實不方便,greenlet對其作了封裝人乓,使其用起來更方便:
首先安裝模塊:
from greenlet import greenlet
import time
def test1():
while True:
print('-------test1------')
g2.switch() #表示切換到g2協(xié)程
time.sleep(1)
def test2():
while True:
print('-------test2-------')
g1.switch() #表示切換到g1協(xié)程
time.sleep(1)
g1 = greenlet(test1)
g2 = greenlet(test2)
g1.switch()#表示切換到g1協(xié)程
這樣就能很方便的控制線程間的切換都毒。
但是在實際問題中自己控制切換是很麻煩的事,要判斷何時切換何時轉(zhuǎn)回來温鸽,在gevent模塊中就完成了自動檢測費(fèi)時操作,轉(zhuǎn)到其他協(xié)程姑尺,然后費(fèi)時結(jié)束后在回來繼續(xù)執(zhí)行蝠猬,其中的底層原理應(yīng)該和select和epoll的消息通知有關(guān)。下面看gevent的使用事例柄粹。
from gevent import monkey
import gevent
from urllib import request
#給原來的io操作加上補(bǔ)丁,使它不堵塞支持協(xié)程
monkey.patch_all()
def download(url):
print('開始下載%s'%url)
result = request.urlopen(url)
print('正在讀取')
s = result.readline()
print('%s里的數(shù)據(jù)為%s'%(url,s))
gevent.joinall(
[gevent.spawn(download,url) for url in ('http://www.baidu.com','http://www.sohu.com','http://www.soso.com') ]
)
運(yùn)行結(jié)果:
開始下載http://www.baidu.com
開始下載http://www.sohu.com
開始下載http://www.soso.com
正在讀取
http://www.sohu.com里的數(shù)據(jù)為b'<!DOCTYPE html>\n'
正在讀取
http://www.baidu.com里的數(shù)據(jù)為b'<!DOCTYPE html>\n'
正在讀取
http://www.soso.com里的數(shù)據(jù)為b'<!DOCTYPE html>\r\n'
從上面結(jié)果可以看出什黑,當(dāng)遇到urlopen'這樣的io操作時堪夭,cpu發(fā)出io操作命令后,就跳到了其他的協(xié)程中森爽,直到io操作結(jié)束才切換回來。
關(guān)于monkey
monky是一種動態(tài)追加功能的補(bǔ)丁橘蜜,利用動態(tài)語言的靈活性付呕,改變內(nèi)建的函數(shù)或?qū)ο蟆Mㄟ^monkey.patch_all(),原來的urlopn已經(jīng)發(fā)生了改變凡涩,不在是原有的堵塞了,而是支持協(xié)程的非堵塞力麸。
from gevent import monkey
from urllib import request
import socket
url = 'http://www.baidu.com'
print('monkey之前')
print(request.urlopen)
print(socket.socket)
monkey.patch_all()
print('monky之后')
print(request.urlopen)
print(socket.socket)
運(yùn)行結(jié)果:
monkey之前
<function urlopen at 0x0000018E24828730>
<class 'socket.socket'>
monky之后
<function urlopen at 0x0000018E24828730>
<class 'gevent._socket3.socket'>
可見monkey后socket已經(jīng)不是原來的socket了育韩,urlopen也應(yīng)該做了相應(yīng)的改變,雖然不知都改了哪里埃叭。
總結(jié)
- greenlet是對協(xié)程的一個封裝悉罕,使的協(xié)程間的切換變得方便易于控制
- gevent實現(xiàn)了自動識別io操作,自動進(jìn)行協(xié)程的切換調(diào)度壁袄。是一種更高級的封裝。