Gevent官網(wǎng)文檔地址:http://www./contents.html 基本概念我們通常所說(shuō)的協(xié)程Coroutine其實(shí)是corporate routine的縮寫,直接翻譯為協(xié)同的例程,一般我們都簡(jiǎn)稱為協(xié)程。 在linux系統(tǒng)中,線程就是輕量級(jí)的進(jìn)程,而我們通常也把協(xié)程稱為輕量級(jí)的線程即微線程。 進(jìn)程和協(xié)程下面對(duì)比一下進(jìn)程和協(xié)程的相同點(diǎn)和不同點(diǎn): 相同點(diǎn): shell進(jìn)程和hello進(jìn)程:
當(dāng)我們掛起一個(gè)執(zhí)行流的時(shí),我們要保存的東西:
而寄存器和棧的結(jié)合就可以理解為上下文,上下文切換的理解: 操作系統(tǒng)保持跟蹤進(jìn)程運(yùn)行所需的所有狀態(tài)信息。這種狀態(tài),就是上下文。 不同點(diǎn):
線程和協(xié)程既然我們上面也說(shuō)了,協(xié)程也被稱為微線程,下面對(duì)比一下協(xié)程和線程:
我們通過(guò)下面的圖更容易理解: 從上圖可以看出,協(xié)程只是在單一的線程里不同的協(xié)程之間切換,其實(shí)和線程很像,線程是在一個(gè)進(jìn)程下,不同的線程之間做切換,這也可能是協(xié)程稱為微線程的原因吧 繼續(xù)分析協(xié)程: GeventGevent是一種基于協(xié)程的Python網(wǎng)絡(luò)庫(kù),它用到Greenlet提供的,封裝了libevent事件循環(huán)的高層同步API。它讓開(kāi)發(fā)者在不改變編程習(xí)慣的同時(shí),用同步的方式寫異步I/O的代碼。 使用Gevent的性能確實(shí)要比用傳統(tǒng)的線程高,甚至高很多。但這里不得不說(shuō)它的一個(gè)坑:
既然Gevent用的是Greenlet,我們通過(guò)下圖來(lái)理解greenlet: 每個(gè)協(xié)程都有一個(gè)parent,最頂層的協(xié)程就是man thread或者是當(dāng)前的線程,每個(gè)協(xié)程遇到IO的時(shí)候就把控制權(quán)交給最頂層的協(xié)程,它會(huì)看那個(gè)協(xié)程的IO event已經(jīng)完成,就將控制權(quán)給它。 下面是greenlet一個(gè)例子 1 from greenlet import greenlet 2 3 def test1(x,y): 4 z = gr2.switch(x+y) 5 print(z) 6 7 8 def test2(u): 9 print(u) 10 gr1.switch(42) 11 12 13 gr1 = greenlet(test1) 14 gr2 = greenlet(test2) 15 16 17 gr1.switch("hello",'world') greenlet(run=None, parent=None): 創(chuàng)建一個(gè)greenlet實(shí)例. 下面是gevent的一個(gè)例子: 1 import gevent 2 3 def func1(): 4 print("start func1") 5 gevent.sleep(1) 6 print("end func1") 7 8 9 def func2(): 10 print("start func2") 11 gevent.sleep(1) 12 print("end func2") 13 14 gevent.joinall( 15 [ 16 gevent.spawn(func1), 17 gevent.spawn(func2) 18 ] 19 ) 關(guān)于gevent中隊(duì)列的使用gevent中也有自己的隊(duì)列,但是有一個(gè)場(chǎng)景我用的過(guò)程中發(fā)現(xiàn)一個(gè)問(wèn)題,就是如果我在協(xié)程中通過(guò)這個(gè)q來(lái)傳遞數(shù)據(jù),如果對(duì)了是空的時(shí)候,從隊(duì)列獲取數(shù)據(jù)的那個(gè)協(xié)程就會(huì)被切換到另外一個(gè)協(xié)程中,這個(gè)協(xié)程用于往隊(duì)列里put放入數(shù)據(jù),問(wèn)題就出在,gevent不認(rèn)為這個(gè)放入數(shù)據(jù)為IO操作,并不會(huì)切換到上一個(gè)協(xié)程中,會(huì)把這個(gè)協(xié)程的任務(wù)完成后在切換到另外一個(gè)協(xié)程。我原本想要實(shí)現(xiàn)的效果是往對(duì)了放入數(shù)據(jù)后就會(huì)切換到get的那個(gè)協(xié)程。(或許我這里理解有問(wèn)題)下面是測(cè)試代碼: 1 import gevent 2 from gevent.queue import Queue 3 4 5 def func(): 6 for i in range(10): 7 8 print("int the func") 9 q.put("test") 10 11 def func2(): 12 for i in range(10): 13 print("int the func2") 14 res = q.get() 15 print("--->",res) 16 17 q = Queue() 18 gevent.joinall( 19 [ 20 gevent.spawn(func2), 21 gevent.spawn(func), 22 ] 23 ) 這段代碼的運(yùn)行效果為: 如果我在fun函數(shù)的q.put("test")后面添加gevent.sleep(0),就會(huì)是如下效果: 原本我預(yù)測(cè)的在不修改代碼的情況下就應(yīng)該是第二個(gè)圖的結(jié)果,但是實(shí)際卻是第一個(gè)圖的結(jié)果(這個(gè)問(wèn)題可能是我自己沒(méi)研究明白,后面繼續(xù)研究) 關(guān)于Gevent的問(wèn)題就像我上面說(shuō)的gevent和第三方庫(kù)配合使用會(huì)有一些問(wèn)題,可以總結(jié)為: 不過(guò)總的來(lái)說(shuō)gevent目前為止還是有很多缺陷,并且不是官網(wǎng)標(biāo)準(zhǔn)庫(kù),而在python3中有一個(gè)官網(wǎng)正在做并且在3.6中已經(jīng)穩(wěn)定的庫(kù)asyncio,這也是一個(gè)非常具有野心的庫(kù),非常建議學(xué)習(xí),我也準(zhǔn)備后面深入了解 |
|