IO多路復(fù)用(IO multiplexing)

對于一個network IO (這里我們以read舉例)辩撑,它會涉及到兩個系統(tǒng)對象:

● 一個是調(diào)用這個IO的process (or thread)
● 一個就是系統(tǒng)內(nèi)核(kernel)

當(dāng)一個read操作發(fā)生時界斜,它會經(jīng)歷兩個階段:

● 等待數(shù)據(jù)準(zhǔn)備,比如accept(), recv()等待數(shù)據(jù) (Waiting for the data to be ready)
● 將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程中, 比如 accept()接受到請求,recv()接收連接發(fā)送的數(shù)據(jù)后需要復(fù)制到內(nèi)核,再從內(nèi)核復(fù)制到進(jìn)程用戶空間(Copying the data from the kernel to the process)

對于socket流而言,數(shù)據(jù)的流向經(jīng)歷兩個階段:

● 第一步通常涉及等待網(wǎng)絡(luò)上的數(shù)據(jù)分組到達(dá),然后被復(fù)制到內(nèi)核的某個緩沖區(qū)合冀。
● 第二步把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用進(jìn)程緩沖區(qū)锄蹂。

IO multiplexing這個詞可能有點陌生,但是如果我說select/epoll水慨,大概就都能明白了得糜。有些地方也稱這種IO方式為事件驅(qū)動IO(event driven IO)。我們都知道晰洒,select/epoll的好處就在于單個process就可以同時處理多個網(wǎng)絡(luò)連接的IO朝抖。它的基本原理就是select/epoll這個function會不斷的輪詢所負(fù)責(zé)的所有socket,當(dāng)某個socket有數(shù)據(jù)到達(dá)了谍珊,就通知用戶進(jìn)程治宣。它的流程如圖:


image.png

當(dāng)用戶進(jìn)程調(diào)用了select,那么整個進(jìn)程會被block砌滞,而同時侮邀,kernel會“監(jiān)視”所有select負(fù)責(zé)的socket,當(dāng)任何一個socket中的數(shù)據(jù)準(zhǔn)備好了贝润,select就會返回绊茧。這個時候用戶進(jìn)程再調(diào)用read操作,將數(shù)據(jù)從kernel拷貝到用戶進(jìn)程打掘。
這個圖和blocking IO的圖其實并沒有太大的不同华畏,事實上還更差一些。因為這里需要使用兩個系統(tǒng)調(diào)用(select和recvfrom)尊蚁,而blocking IO只調(diào)用了一個系統(tǒng)調(diào)用(recvfrom)亡笑。但是,用select的優(yōu)勢在于它可以同時處理多個connection.

強(qiáng)調(diào):
1. 如果處理的連接數(shù)不是很高的話横朋,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好仑乌,可能延遲還更大。select/epoll的優(yōu)勢并不是對于單個連接能處理得更快琴锭,而是在于能處理更多的連接晰甚。

2. 在多路復(fù)用模型中,對于每一個socket祠够,一般都設(shè)置成為non-blocking压汪,但是,如上圖所示古瓤,整個用戶的process其實是一直被block的。只不過process是被select這個函數(shù)block,而不是被socket IO給block落君。
結(jié)論: select的優(yōu)勢在于可以處理多個連接穿香,不適用于單個連接。
#服務(wù)端
from socket import *
import select
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8093))
server.listen(5)
server.setblocking(False)
print('starting...')

rlist=[server,]
wlist=[]
wdata={}

while True:
    rl,wl,xl=select.select(rlist,wlist,[],0.5)
    print(wl)
    for sock in rl:
        if sock == server:
            conn,addr=sock.accept()
            rlist.append(conn)
        else:
            try:
                data=sock.recv(1024)
                if not data:
                    sock.close()
                    rlist.remove(sock)
                    continue
                wlist.append(sock)
                wdata[sock]=data.upper()
            except Exception:
                sock.close()
                rlist.remove(sock)

    for sock in wl:
        sock.send(wdata[sock])
        wlist.remove(sock)
        wdata.pop(sock)

#客戶端
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8093))


while True:
    msg=input('>>: ').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))

client.close()

select網(wǎng)絡(luò)IO模型

在IO multiplexing Model中绎速,

實際中皮获,對于每一個socket,一般都設(shè)置成為non-blocking纹冤,因為只有設(shè)置成non-blocking 才能使單個線程/進(jìn)程不被阻塞(或者說鎖兹鞅Α),可以繼續(xù)處理其他socket萌京。如上圖所示雁歌,整個用戶的process其實是一直被block的。只不過process是被select這個函數(shù)block知残,而不是被socket IO給block靠瞎。
select監(jiān)聽fd變化的過程分析:

用戶進(jìn)程創(chuàng)建socket對象,拷貝監(jiān)聽的fd到內(nèi)核空間求妹,每一個fd會對應(yīng)一張系統(tǒng)文件表乏盐,內(nèi)核空間的fd響應(yīng)到數(shù)據(jù)后,就會發(fā)送信號給用戶進(jìn)程數(shù)據(jù)已到制恍;
用戶進(jìn)程再發(fā)送系統(tǒng)調(diào)用父能,比如(accept)將內(nèi)核空間的數(shù)據(jù)copy到用戶空間,同時作為接受數(shù)據(jù)端內(nèi)核空間的數(shù)據(jù)清除净神,這樣重新監(jiān)聽時fd再有新的數(shù)據(jù)又可以響應(yīng)到了(發(fā)送端因為基于TCP協(xié)議所以需要收到應(yīng)答后才會清除)法竞。

所以, IO多路復(fù)用,本質(zhì)上不會有并發(fā)的功能强挫,因為任何時候還是只有一個進(jìn)程或線程進(jìn)行工作岔霸,它之所以能提高效率是因為select\epoll 把進(jìn)來的socket放到他們的 '監(jiān)視' 列表里面,當(dāng)任何socket有可讀可寫數(shù)據(jù)立馬處理俯渤,那如果select\epoll 手里同時檢測著很多socket呆细, 一有動靜馬上返回給進(jìn)程處理,總比一個一個socket過來,阻塞等待,處理高效率八匠。
該模型的優(yōu)點:

相比其他模型絮爷,使用select() 的事件驅(qū)動模型只用單線程(進(jìn)程)執(zhí)行,占用資源少梨树,不消耗太多 CPU坑夯,同時能夠為多客戶端提供服務(wù)。如果試圖建立一個簡單的事件驅(qū)動的服務(wù)器程序抡四,這個模型有一定的參考價值

該模型的缺點:

首先select()接口并不是實現(xiàn)“事件驅(qū)動”的最好選擇柜蜈。因為當(dāng)需要探測的句柄值較大時仗谆,select()接口本身需要消耗大量時間去輪詢各個句柄。很多操作系統(tǒng)提供了更為高效的接口淑履,如linux提供了epoll隶垮,BSD提供了kqueue,Solaris提供了/dev/poll秘噪,…狸吞。如果需要實現(xiàn)更高效的服務(wù)器程序,類似epoll這樣的接口更被推薦指煎。遺憾的是不同的操作系統(tǒng)特供的epoll接口有很大差異蹋偏,所以使用類似于epoll的接口實現(xiàn)具有較好跨平臺能力的服務(wù)器會比較困難。

其次至壤,該模型將事件探測和事件響應(yīng)夾雜在一起威始,一旦事件響應(yīng)的執(zhí)行體龐大,則對整個模型是災(zāi)難性的崇渗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末字逗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宅广,更是在濱河造成了極大的恐慌葫掉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跟狱,死亡現(xiàn)場離奇詭異俭厚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)驶臊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門挪挤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人关翎,你說我怎么就攤上這事扛门。” “怎么了纵寝?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵论寨,是天一觀的道長。 經(jīng)常有香客問我爽茴,道長葬凳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任室奏,我火速辦了婚禮火焰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胧沫。我一直安慰自己昌简,他們只是感情好占业,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著江场,像睡著了一般纺酸。 火紅的嫁衣襯著肌膚如雪窖逗。 梳的紋絲不亂的頭發(fā)上址否,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音碎紊,去河邊找鬼佑附。 笑死捂敌,一個胖子當(dāng)著我的面吹牛昌执,可吹牛的內(nèi)容都是我干的聋迎。 我是一名探鬼主播志珍,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼读拆,長吁一口氣:“原來是場噩夢啊……” “哼惑申!你這毒婦竟也來了侍筛?” 一聲冷哼從身側(cè)響起髓绽,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锅锨,失蹤者是張志新(化名)和其女友劉穎叽赊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體必搞,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡必指,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了恕洲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塔橡。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖霜第,靈堂內(nèi)的尸體忽然破棺而出葛家,到底是詐尸還是另有隱情,我是刑警寧澤泌类,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布癞谒,位于F島的核電站,受9級特大地震影響末誓,放射性物質(zhì)發(fā)生泄漏扯俱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一喇澡、第九天 我趴在偏房一處隱蔽的房頂上張望迅栅。 院中可真熱鬧,春花似錦晴玖、人聲如沸读存。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽让簿。三九已至敬察,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尔当,已是汗流浹背莲祸。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留椭迎,地道東北人锐帜。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像畜号,于是被迫代替她去往敵國和親缴阎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 本文摘抄自linux基礎(chǔ)編程 IO概念 Linux的內(nèi)核將所有外部設(shè)備都可以看做一個文件來操作简软。那么我們對與外部設(shè)...
    VD2012閱讀 1,021評論 0 2
  • 本文摘抄自linux基礎(chǔ)編程 IO概念 Linux的內(nèi)核將所有外部設(shè)備都可以看做一個文件來操作蛮拔。那么我們對與外部設(shè)...
    lintong閱讀 1,582評論 0 4
  • https://segmentfault.com/a/1190000003063859 blocking和non-...
    yeying12321閱讀 790評論 0 2
  • 我們總是為自己沒有完成任務(wù)找各種借口:我加班太晚了惋砂,孩子一直再鬧人,朋友好久沒見要聚餐等等绳锅,我們訂的計劃一而再西饵,再...
    遇見桃子閱讀 455評論 0 2
  • 一.昏暗 動手之前看了一眼時間,2016/12/14鳞芙,電腦的燈光閃爍提醒著還在人間眷柔。 十二月十四有何特殊含義嗎,我...
    Veia閱讀 178評論 0 0