一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Python并發(fā)編程協(xié)程(Coroutine)之Gevent

 文炳春秋 2020-09-08

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):
我們都可以把他們看做是一種執(zhí)行流,執(zhí)行流可以掛起,并且后面可以在你掛起的地方恢復(fù)執(zhí)行,這實(shí)際上都可以看做是continuation,關(guān)于這個(gè)我們可以通過(guò)在linux上運(yùn)行一個(gè)hello程序來(lái)理解:

shell進(jìn)程和hello進(jìn)程:

  1. 開(kāi)始,shell進(jìn)程在運(yùn)行,等待命令行的輸入
  2. 執(zhí)行hello程序,shell通過(guò)系統(tǒng)調(diào)用來(lái)執(zhí)行我們的請(qǐng)求,這個(gè)時(shí)候系統(tǒng)調(diào)用會(huì)講控制權(quán)傳遞給操作系統(tǒng)。操作系統(tǒng)保存shell進(jìn)程的上下文,創(chuàng)建一個(gè)hello進(jìn)程以及其上下文并將控制權(quán)給新的hello進(jìn)程。
  3. hello進(jìn)程終止后,操作系統(tǒng)恢復(fù)shell進(jìn)程的上下文,并將控制權(quán)傳回給shell進(jìn)程
  4. shell進(jìn)程繼續(xù)等待下個(gè)命令的輸入

當(dāng)我們掛起一個(gè)執(zhí)行流的時(shí),我們要保存的東西:

  1. 棧, 其實(shí)在你切換前你的局部變量,以及要函數(shù)的調(diào)用都需要保存,否則都無(wú)法恢復(fù)
  2. 寄存器狀態(tài),這個(gè)其實(shí)用于當(dāng)你的執(zhí)行流恢復(fù)后要做什么

而寄存器和棧的結(jié)合就可以理解為上下文,上下文切換的理解:
CPU看上去像是在并發(fā)的執(zhí)行多個(gè)進(jìn)程,這是通過(guò)處理器在進(jìn)程之間切換來(lái)實(shí)現(xiàn)的,操作系統(tǒng)實(shí)現(xiàn)這種交錯(cuò)執(zhí)行的機(jī)制稱為上下文切換

操作系統(tǒng)保持跟蹤進(jìn)程運(yùn)行所需的所有狀態(tài)信息。這種狀態(tài),就是上下文。
在任何一個(gè)時(shí)刻,操作系統(tǒng)都只能執(zhí)行一個(gè)進(jìn)程代碼,當(dāng)操作系統(tǒng)決定把控制權(quán)從當(dāng)前進(jìn)程轉(zhuǎn)移到某個(gè)新進(jìn)程時(shí),就會(huì)進(jìn)行上下文切換,即保存當(dāng)前進(jìn)程的上下文,恢復(fù)新進(jìn)程的上下文,然后將控制權(quán)傳遞到新進(jìn)程,新進(jìn)程就會(huì)從它上次停止的地方開(kāi)始。

不同點(diǎn):

  1. 執(zhí)行流的調(diào)度者不同,進(jìn)程是內(nèi)核調(diào)度,而協(xié)程是在用戶態(tài)調(diào)度,也就是說(shuō)進(jìn)程的上下文是在內(nèi)核態(tài)保存恢復(fù)的,而協(xié)程是在用戶態(tài)保存恢復(fù)的,很顯然用戶態(tài)的代價(jià)更低
  2. 進(jìn)程會(huì)被強(qiáng)占,而協(xié)程不會(huì),也就是說(shuō)協(xié)程如果不主動(dòng)讓出CPU,那么其他的協(xié)程,就沒(méi)有執(zhí)行的機(jī)會(huì)。
  3. 對(duì)內(nèi)存的占用不同,實(shí)際上協(xié)程可以只需要4K的棧就足夠了,而進(jìn)程占用的內(nèi)存要大的多
  4. 從操作系統(tǒng)的角度講,多協(xié)程的程序是單進(jìn)程,單協(xié)程

線程和協(xié)程

既然我們上面也說(shuō)了,協(xié)程也被稱為微線程,下面對(duì)比一下協(xié)程和線程:

  1. 線程之間需要上下文切換成本相對(duì)協(xié)程來(lái)說(shuō)是比較高的,尤其在開(kāi)啟線程較多時(shí),但協(xié)程的切換成本非常低。
  2. 同樣的線程的切換更多的是靠操作系統(tǒng)來(lái)控制,而協(xié)程的執(zhí)行由我們自己控制

我們通過(guò)下面的圖更容易理解:

從上圖可以看出,協(xié)程只是在單一的線程里不同的協(xié)程之間切換,其實(shí)和線程很像,線程是在一個(gè)進(jìn)程下,不同的線程之間做切換,這也可能是協(xié)程稱為微線程的原因吧

繼續(xù)分析協(xié)程:

Gevent

Gevent是一種基于協(xié)程的Python網(wǎng)絡(luò)庫(kù),它用到Greenlet提供的,封裝了libevent事件循環(huán)的高層同步API。它讓開(kāi)發(fā)者在不改變編程習(xí)慣的同時(shí),用同步的方式寫異步I/O的代碼。

使用Gevent的性能確實(shí)要比用傳統(tǒng)的線程高,甚至高很多。但這里不得不說(shuō)它的一個(gè)坑:

  1. Monkey-patching,我們都叫猴子補(bǔ)丁,因?yàn)槿绻褂昧诉@個(gè)補(bǔ)丁,Gevent直接修改標(biāo)準(zhǔn)庫(kù)里面大部分的阻塞式系統(tǒng)調(diào)用,包括socket、ssl、threading和 select等模塊,而變?yōu)閰f(xié)作式運(yùn)行。但是我們無(wú)法保證你在復(fù)雜的生產(chǎn)環(huán)境中有哪些地方使用這些標(biāo)準(zhǔn)庫(kù)會(huì)由于打了補(bǔ)丁而出現(xiàn)奇怪的問(wèn)題
  2. 第三方庫(kù)支持。得確保項(xiàng)目中用到其他用到的網(wǎng)絡(luò)庫(kù)也必須使用純Python或者明確說(shuō)明支持Gevent

既然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è)例子

復(fù)制代碼
 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')
復(fù)制代碼

greenlet(run=None, parent=None): 創(chuàng)建一個(gè)greenlet實(shí)例.
gr.parent:每一個(gè)協(xié)程都有一個(gè)父協(xié)程,當(dāng)前協(xié)程結(jié)束后會(huì)回到父協(xié)程中執(zhí)行,該 屬性默認(rèn)是創(chuàng)建該協(xié)程的協(xié)程.
gr.run: 該屬性是協(xié)程實(shí)際運(yùn)行的代碼. run方法結(jié)束了,那么該協(xié)程也就結(jié)束了.
gr.switch(*args, **kwargs): 切換到gr協(xié)程.
gr.throw(): 切換到gr協(xié)程,接著拋出一個(gè)異常.

下面是gevent的一個(gè)例子:

復(fù)制代碼
 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 )
復(fù)制代碼

關(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è)試代碼:

復(fù)制代碼
 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 )
復(fù)制代碼

這段代碼的運(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é)為:
python協(xié)程的庫(kù)可以直接monkey path 
C寫成的庫(kù)可以采用豆瓣開(kāi)源的greenify來(lái)打patch(這個(gè)功能自己準(zhǔn)備后面做測(cè)試)

不過(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)備后面深入了解

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    91精品日本在线视频| 男生和女生哪个更好色| 亚洲一区二区三区在线免费| 欧美日韩高清不卡在线播放| 精品国产日韩一区三区| 女生更色还是男生更色| 在线免费国产一区二区| 成人欧美精品一区二区三区| 国产一区二区三区草莓av| 丰满熟女少妇一区二区三区| 成人午夜爽爽爽免费视频| 欧美日韩国产一级91| 亚洲国产一级片在线观看| 欧洲日本亚洲一区二区| 丝袜美女诱惑在线观看| 一区二区三区人妻在线| 国产一区欧美一区日本道| 久热香蕉精品视频在线播放| 丰满人妻熟妇乱又乱精品古代| 日本不卡在线一区二区三区| 伊人久久青草地综合婷婷| 国产麻豆成人精品区在线观看| 黄色国产精品一区二区三区| 超碰在线播放国产精品| 亚洲免费视频中文字幕在线观看 | 中文人妻精品一区二区三区四区 | 日韩欧美中文字幕av| 欧美激情区一区二区三区| 色鬼综合久久鬼色88| 91播色在线免费播放| 国产精品一区二区三区日韩av| 九九热视频免费在线视频| 久久99青青精品免费观看| 有坂深雪中文字幕亚洲中文| 国产一级不卡视频在线观看| 国产精品不卡一区二区三区四区| 国产精品免费视频视频| 日本女优一区二区三区免费| 韩国日本欧美国产三级| 高潮少妇高潮久久精品99| 日韩人妻有码一区二区|