Linux網(wǎng)絡IO模型

什么是同步與異步跌造、阻塞與非阻塞

引用知乎 怎樣理解阻塞非阻塞與同步異步的區(qū)別定罢? 上面的一個回答,很生動的說明了同步異步淳玩,阻塞非阻塞之間的區(qū)別聯(lián)系:


老張愛喝茶直撤,廢話不說,煮開水蜕着。

出場人物:老張谋竖,水壺兩把(普通水壺,簡稱水壺承匣;會響的水壺蓖乘,簡稱響水壺)。

1 老張把水壺放到火上韧骗,立等水開嘉抒。(同步阻塞)

老張覺得自己有點傻

2 老張把水壺放到火上,去客廳看電視袍暴,時不時去廚房看看水開沒有些侍。(同步非阻塞)

老張還是覺得自己有點傻,于是變高端了政模,買了把會響笛的那種水壺娩梨。水開之后,能大聲發(fā)出嘀~~~~的噪音览徒。

3 老張把響水壺放到火上狈定,立等水開。(異步阻塞)

老張覺得這樣傻等意義不大

4 老張把響水壺放到火上习蓬,去客廳看電視纽什,水壺響之前不再去看它了,響了再去拿壺躲叼。(異步非阻塞)

老張覺得自己聰明了芦缰。

所謂同步異步,只是對于水壺而言枫慷。普通水壺让蕾,同步浪规;響水壺,異步探孝。雖然都能干活笋婿,但響水壺可以在自己完工之后,提示老張水開了顿颅。這是普通水壺所不能及的缸濒。同步只能讓調(diào)用者去輪詢自己(情況2中),造成老張效率的低下粱腻。

所謂阻塞非阻塞庇配,僅僅對于老張而言。立等的老張绍些,阻塞捞慌;看電視的老張,非阻塞柬批。情況1和情況3中老張就是阻塞的啸澡,媳婦喊他都不知道。雖然3中響水壺是異步的萝快,可對于立等的老張沒有太大的意義锻霎。所以一般異步是配合非阻塞使用的,這樣才能發(fā)揮異步的效用揪漩。


看上面的例子旋恼,我們再來關注Linux網(wǎng)絡IO模型,然后結(jié)合這個例子去理解奄容。

Linux網(wǎng)絡IO模型

Unix提供了五種IO模式冰更,分別是:

  • 阻塞IO

  • 非阻塞IO

  • IO復用

  • 信號驅(qū)動IO

  • 異步IO

在之前的學習中我們也了解了從用戶進程到底層硬件執(zhí)行IO的過程,以read為例:

image.png

數(shù)據(jù)需要從硬件設備拷貝到內(nèi)核空間的緩沖區(qū)昂勒,然后從內(nèi)核緩沖區(qū)拷貝到用戶進程空間蜀细。

我們把數(shù)據(jù)需要從硬件設備拷貝到內(nèi)核空間的緩沖區(qū)這個過程類比為燒水,從內(nèi)核緩沖區(qū)拷貝到用戶進程空間這個過程類比為用燒好的水泡茶戈盈。

阻塞IO

image.png

阻塞IO是最常用的IO模型奠衔,我們在java中調(diào)用傳統(tǒng)BIO(InputStream、OutpuytStream)的讀寫方法都是這種IO模型塘娶。

觀察上圖归斤,在進程空間中調(diào)用recvfrom,其系統(tǒng)調(diào)用直到數(shù)據(jù)從硬件設備拷貝到內(nèi)核緩沖區(qū)并且從內(nèi)核拷貝到用戶進程空間時才會返回刁岸,在此期間一直是阻塞的脏里,進程在從調(diào)用recvfrom到他返回這段時間一直都是阻塞的,故稱為阻塞IO虹曙。

阻塞IO對應了我們上面提到的同步阻塞迫横。在這種IO模式下整個過程相當于使用不會響的普通水壺燒水番舆,并且老張一直在旁邊盯著,干不了其他事矾踱。水燒好后老張再去泡茶恨狈。整個過程是同步阻塞的。

在阻塞IO模式下介返,在同一個線程當中拴事,我們對于多個連接沃斤,只能依次處理:

while true {
    for i in stream[] {
        //可能會阻塞很長時間
        read until available 
    }
}

非阻塞IO

image.png

用戶進程發(fā)起一個recvfrom調(diào)用的時候圣蝎,如果內(nèi)核緩沖區(qū)的數(shù)據(jù)還沒有準備好(沒有完全從硬件拷貝到內(nèi)核),那么他不會阻塞用戶進程衡瓶,而是立刻返回一個error徘公。用戶發(fā)起一個recvfrom操作之后,不需要等待哮针,而是馬上會得到一個結(jié)果关面,用戶可以判斷這個結(jié)果,如果是一個error十厢,表示數(shù)據(jù)還沒有準備好等太,于是可以再次發(fā)起recvfrom操作,一旦內(nèi)核數(shù)據(jù)準備好了蛮放,就可以把數(shù)據(jù)拷貝到用戶進程空間缩抡,然后返回。

這種IO模型稱之為非阻塞IO包颁,整個過程可以類比為:在這種IO模式下調(diào)用recvfrom相當于使用不會響的普通水壺燒水柳恐,老張時不時跑到廚房看看水燒開了沒(這個過程是同步非阻塞的)栗恩,如果水燒開了,他就用燒開的水泡茶(相當于從內(nèi)核copy數(shù)據(jù)到用戶空間這一段,這個過程其實是同步阻塞的)

在非阻塞IO模式下歼跟,我們發(fā)現(xiàn)可以在一個線程中處理多個連接了:

// 忙輪詢
while true {
    for i in stream[]; {
        // 如果數(shù)據(jù)沒有準備好,就立即返回愧驱,處理下一個流
        read until unavailable 
    }
}

我們只要不停的把所有流從頭到尾問一遍派桩,又從頭開始。這樣就可以處理多個流了贵少,但這樣的做法顯然不好呵俏,因為如果所有的流都沒有數(shù)據(jù),那么只會白白浪費CPU春瞬。

為了避免CPU空轉(zhuǎn)柴信,可以引進了一個代理: select或poll(兩者本質(zhì)上相同)

IO復用

image.png

Linux 提供了select/poll,進程將一個或多個fd傳遞給select或poll系統(tǒng)調(diào)用宽气,并且阻塞在select或poll方法上随常。同時潜沦,kernel會偵測所有select負責的fd是否處于就緒狀態(tài),如果有任何一個fd就緒绪氛,select或poll就會返回唆鸡,這個時候用戶進程再調(diào)用recvfrom,將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶進程空間枣察。

這個圖和blocking IO的圖有些相似争占,但是還有一些區(qū)別。因為這里需要使用兩個system call (select 和 recvfrom)序目,而blocking IO只調(diào)用了一個system call (recvfrom)臂痕。但是,用select的優(yōu)勢在于它可以同時處理多個connection猿涨。

while true {
    // 在select上阻塞
    select(streams[])
    // 無差別輪詢
    for i in streams[] {
        read until unavailable
    }
}

于是握童,如果沒有I/O事件產(chǎn)生,我們的程序就會阻塞在select處叛赚。但是依然有個問題澡绩,我們從select那里僅僅知道了,有I/O事件發(fā)生了俺附,但卻并不知道是那幾個流(可能有一個肥卡,多個,甚至全部)事镣,我們只能無差別輪詢所有流步鉴,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流蛮浑,對他們進行操作唠叛。使用select,我們有O(n)的無差別輪詢復雜度沮稚,同時處理的流越多艺沼,每一次無差別輪詢時間就越長。

Linux還提供了一個epoll系統(tǒng)調(diào)用蕴掏,不同于忙輪詢和無差別輪詢障般,epoll之會把哪個流發(fā)生了怎樣的I/O事件通知我們。此時我們對這些流的操作都是有意義的(復雜度降低到了O(1))盛杰。

// 事先調(diào)用epoll_ctl注冊感興趣的事件到epollfd
while true {
    // 返回觸發(fā)注冊事件的流
    active_stream[] = epoll_wait(epollfd)
    // 無須遍歷所有的流
    for i in active_stream[] {
        read or write till
    }
}

信號驅(qū)動IO

首先開啟套接口信號驅(qū)動IO功能挽荡,并通過系統(tǒng)調(diào)用sigaction執(zhí)行一個信號處理函數(shù),此系統(tǒng)調(diào)用立即返回即供。當數(shù)據(jù)準備就緒時定拟,就為該進程生成一個sigio信號,通過信號回調(diào)通知進程逗嫡。進程調(diào)用recvfrom讀取數(shù)據(jù)青自,將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶進程空間株依。

上面的過程可以類比為:老張使用會響的水壺燒水,然后就去客廳看電視了延窜。水燒好后水壺響起來(這個過程是異步非阻塞的)恋腕,老張再來廚房用燒好的水泡茶(這個過程是同步阻塞的)。

異步IO

image.png

用戶進程發(fā)起recvfrom操作之后逆瑞,立刻就可以開始去做其它的事荠藤。而另一方面,從kernel的角度获高,當它收到一個asynchronous read之后哈肖,首先它會立刻返回,所以不會對用戶進程產(chǎn)生任何block谋减。然后牡彻,kernel會等待數(shù)據(jù)準備完成扫沼,然后將數(shù)據(jù)拷貝到用戶內(nèi)存出爹,當這一切都完成之后,kernel會給用戶進程發(fā)送一個signal缎除,告訴它read操作完成了严就。

這種IO模式與信號驅(qū)動IO的區(qū)別在于:信號驅(qū)動IO由內(nèi)核通知我們什么時候可以開始一個IO操作,異步IO則由內(nèi)核告訴我們IO操作何時完成器罐。

異步IO模式可以類比為:在這種IO模式下整個過程相當于使用會響的水壺燒水梢为,并且,這個水壺更加智能轰坊,水燒好后可以自動泡茶铸董,然后發(fā)出聲響通知老張。老張把水放到火上就去客廳看電視了肴沫,水燒好并且茶葉泡好之后粟害,水壺發(fā)出聲響通知老張。

參考

Linux IO模式及 select颤芬、poll悲幅、epoll詳解

怎樣理解阻塞非阻塞與同步異步的區(qū)別?

epoll 或者 kqueue 的原理是什么站蝠?

《Netty權(quán)威指南》 電子工業(yè)出版社

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末汰具,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子菱魔,更是在濱河造成了極大的恐慌留荔,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澜倦,死亡現(xiàn)場離奇詭異聚蝶,居然都是意外死亡拔疚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門既荚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稚失,“玉大人,你說我怎么就攤上這事恰聘【涓鳎” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵晴叨,是天一觀的道長凿宾。 經(jīng)常有香客問我,道長兼蕊,這世上最難降的妖魔是什么初厚? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮孙技,結(jié)果婚禮上产禾,老公的妹妹穿的比我還像新娘。我一直安慰自己牵啦,他們只是感情好亚情,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哈雏,像睡著了一般楞件。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上裳瘪,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天土浸,我揣著相機與錄音,去河邊找鬼彭羹。 笑死黄伊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的皆怕。 我是一名探鬼主播毅舆,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼愈腾!你這毒婦竟也來了憋活?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤虱黄,失蹤者是張志新(化名)和其女友劉穎悦即,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡辜梳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年粱甫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片作瞄。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡茶宵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宗挥,到底是詐尸還是另有隱情乌庶,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布契耿,位于F島的核電站瞒大,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏搪桂。R本人自食惡果不足惜透敌,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望踢械。 院中可真熱鬧酗电,春花似錦、人聲如沸裸燎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽德绿。三九已至,卻和暖如春退渗,著一層夾襖步出監(jiān)牢的瞬間移稳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工会油, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留个粱,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓翻翩,卻偏偏與公主長得像都许,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嫂冻,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348

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