IO 模型知多少 | 理論篇

1. 引言

同步異步I/O瓷耙,阻塞非阻塞I/O是程序員老生常談的話題了超升,也是自己一直以來懵懵懂懂的一個話題。比如:何為同步異步哺徊?何為阻塞與非阻塞?二者的區(qū)別在哪里乾闰?阻塞在何處落追?為什么會有多種IO模型,分別用來解決問題涯肩?常用的框架采用的是何種I/O模型轿钠?各種IO模型的優(yōu)劣勢在哪里,適用于何種應(yīng)用場景病苗?

簡而言之疗垛,對于I/O的認(rèn)知,不能僅僅停留在字面上認(rèn)識硫朦,了解內(nèi)部玄機(jī)贷腕,才能深刻理解I/O,才能看清I/O相關(guān)問題的本質(zhì)。

2. I/O 的定義

I/O 的全稱是Input/Output泽裳。雖常談及I/O瞒斩,但想必你也一時不能給出一個完整的定義。搜索了谷歌涮总,發(fā)現(xiàn)也盡是些冗長的論述胸囱。要想厘清I/O這個概念,我們需要從不同的視角去理解它瀑梗。

2.1. 計(jì)算機(jī)視角

馮?諾伊曼計(jì)算機(jī)的基本思想中有提到計(jì)算機(jī)硬件組成應(yīng)為五大部分:控制器烹笔,運(yùn)算器,存儲器抛丽,輸入和輸出谤职。其中輸入是指將數(shù)據(jù)輸入到計(jì)算機(jī)的設(shè)備,比如鍵盤鼠標(biāo)铺纽;輸出是指從計(jì)算機(jī)中獲取數(shù)據(jù)的設(shè)備柬帕,比如顯示器;以及既是輸入又是輸出設(shè)備狡门,硬盤陷寝,網(wǎng)卡等。

用戶通過操作系統(tǒng)才能完成對計(jì)算機(jī)的操作其馏。計(jì)算機(jī)啟動時凤跑,第一個啟動的程序是操作系統(tǒng)的內(nèi)核,它將負(fù)責(zé)計(jì)算機(jī)的資源管理和進(jìn)程的調(diào)度叛复。換句話說:操作系統(tǒng)負(fù)責(zé)從輸入設(shè)備讀取數(shù)據(jù)并將數(shù)據(jù)寫入到輸出設(shè)備仔引。

所以I/O之于計(jì)算機(jī),有兩層意思:

  1. I/O設(shè)備
  2. 對I/O設(shè)備的數(shù)據(jù)讀寫

對于一次I/O操作褐奥,必然涉及2個參與方咖耘,一個輸入端,一個輸出端撬码,而又根據(jù)參與雙方的設(shè)備類型儿倒,我們又可以分為磁盤I/O,網(wǎng)絡(luò)I/O(一次網(wǎng)絡(luò)的請求響應(yīng)呜笑,網(wǎng)卡)等夫否。

2.2. 程序視角

應(yīng)用程序作為一個文件保存在磁盤中,只有加載到內(nèi)存到成為一個進(jìn)程才能運(yùn)行叫胁。應(yīng)用程序運(yùn)行在計(jì)算機(jī)內(nèi)存中凰慈,必然會涉及到數(shù)據(jù)交換,比如讀寫磁盤文件驼鹅,訪問數(shù)據(jù)庫微谓,調(diào)用遠(yuǎn)程API等等森篷。但我們編寫的程序并不能像操作系統(tǒng)內(nèi)核一樣直接進(jìn)行I/O操作。

因?yàn)闉榱舜_保操作系統(tǒng)的安全穩(wěn)定運(yùn)行堰酿,操作系統(tǒng)啟動后疾宏,將會開啟保護(hù)模式:將內(nèi)存分為內(nèi)核空間(內(nèi)核對應(yīng)進(jìn)程所在內(nèi)存空間)和用戶空間,進(jìn)行內(nèi)存隔離触创。我們構(gòu)建的程序?qū)⑦\(yùn)行在用戶空間坎藐,用戶空間無法操作內(nèi)核空間,也就意味著用戶空間的程序不能直接訪問由內(nèi)核管理的I/O哼绑,比如:硬盤岩馍、網(wǎng)卡等。

但操作系統(tǒng)向外提供API抖韩,其由各種類型的系統(tǒng)調(diào)用(System Call)組成蛀恩,以提供安全的訪問控制。
所以應(yīng)用程序要想訪問內(nèi)核管理的I/O茂浮,必須通過調(diào)用內(nèi)核提供的系統(tǒng)調(diào)用(system call)進(jìn)行間接訪問双谆。

所以I/O之于應(yīng)用程序來說,強(qiáng)調(diào)的通過向內(nèi)核發(fā)起系統(tǒng)調(diào)用完成對I/O的間接訪問席揽。換句話說應(yīng)用程序發(fā)起的一次IO操作實(shí)際包含兩個階段:

  1. IO調(diào)用階段:應(yīng)用程序進(jìn)程向內(nèi)核發(fā)起系統(tǒng)調(diào)用
  2. IO執(zhí)行階段:內(nèi)核執(zhí)行IO操作并返回
    2.1. 準(zhǔn)備數(shù)據(jù)階段:內(nèi)核等待I/O設(shè)備準(zhǔn)備好數(shù)據(jù)
    2.2. 拷貝數(shù)據(jù)階段:將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶空間緩沖區(qū)

怎么理解準(zhǔn)備數(shù)據(jù)階段呢顽馋?
對于寫請求:等待系統(tǒng)調(diào)用的完整請求數(shù)據(jù),并寫入內(nèi)核緩沖區(qū)幌羞;
對于讀請求:等待系統(tǒng)調(diào)用的完整請求數(shù)據(jù)寸谜;(若請求數(shù)據(jù)不存在于內(nèi)核緩沖區(qū))則將外圍設(shè)備的數(shù)據(jù)讀入到內(nèi)核緩沖區(qū)。

IO操作執(zhí)行流程

而應(yīng)用程序進(jìn)程在發(fā)起IO調(diào)用至內(nèi)核執(zhí)行IO返回之前属桦,應(yīng)用程序進(jìn)程/線程所處狀態(tài)熊痴,就是我們下面要討論的第二個話題阻塞IO與非阻塞IO。

3. IO 模型之阻塞I/O(BIO)

應(yīng)用程序中進(jìn)程在發(fā)起IO調(diào)用后至內(nèi)核執(zhí)行IO操作返回結(jié)果之前聂宾,若發(fā)起系統(tǒng)調(diào)用的線程一直處于等待狀態(tài)果善,則此次IO操作為阻塞IO。阻塞IO簡稱BIO系谐,Blocking IO岭埠。其處理流程如下圖所示:

BIO

從上圖可知當(dāng)用戶進(jìn)程發(fā)起IO系統(tǒng)調(diào)用后,內(nèi)核從準(zhǔn)備數(shù)據(jù)到拷貝數(shù)據(jù)到用戶空間的兩個階段期間用戶調(diào)用線程選擇阻塞等待數(shù)據(jù)返回蔚鸥。

因此BIO帶來了一個問題:如果內(nèi)核數(shù)據(jù)需要耗時很久才能準(zhǔn)備好,那么用戶進(jìn)程將被阻塞许赃,浪費(fèi)性能止喷。為了提升應(yīng)用的性能,雖然可以通過多線程來提升性能混聊,但線程的創(chuàng)建依然會借助系統(tǒng)調(diào)用弹谁,同時多線程會導(dǎo)致頻繁的線程上下文的切換,同樣會影響性能。所以要想解決BIO帶來的問題预愤,我們就得看到問題的本質(zhì)沟于,那就是阻塞二字。

4. IO 模型之非阻塞I/O(NIO)

那解決方案自然也容易想到植康,將阻塞變?yōu)榉亲枞跆蔷褪怯脩暨M(jìn)程在發(fā)起系統(tǒng)調(diào)用時指定為非阻塞,內(nèi)核接收到請求后销睁,就會立即返回供璧,然后用戶進(jìn)程通過輪詢的方式來拉取處理結(jié)果。也就是如下圖所示:

NIO

應(yīng)用程序中進(jìn)程在發(fā)起IO調(diào)用后至內(nèi)核執(zhí)行IO操作返回結(jié)果之前冻记,若發(fā)起系統(tǒng)調(diào)用的線程不會等待而是立即返回睡毒,則此次IO操作為非阻塞IO模型。非阻塞IO簡稱NIO冗栗,Non-Blocking IO演顾。

然而,非阻塞IO雖然相對于阻塞IO大幅提升了性能隅居,但依舊不是完美的解決方案钠至,其依然存在性能問題,也就是頻繁的輪詢導(dǎo)致頻繁的系統(tǒng)調(diào)用军浆,會耗費(fèi)大量的CPU資源棕洋。比如當(dāng)并發(fā)很高時,假設(shè)有1000個并發(fā)乒融,那么單位時間循環(huán)內(nèi)將會有1000次系統(tǒng)調(diào)用去輪詢執(zhí)行結(jié)果掰盘,而實(shí)際上可能只有2個請求結(jié)果執(zhí)行完畢,這就會有998次無效的系統(tǒng)調(diào)用赞季,造成嚴(yán)重的性能浪費(fèi)愧捕。有問題就要解決,那NIO問題的本質(zhì)就是頻繁輪詢導(dǎo)致的無效系統(tǒng)調(diào)用申钩。

5. IO模型之IO多路復(fù)用

解決NIO的思路就是降解無效的系統(tǒng)調(diào)用次绘,如何降解呢?我們一起來看看以下幾種IO多路復(fù)用的解決思路撒遣。

5.1. IO多路復(fù)用之select/poll

Select是內(nèi)核提供的系統(tǒng)調(diào)用邮偎,它支持一次查詢多個系統(tǒng)調(diào)用的可用狀態(tài),當(dāng)任意一個結(jié)果狀態(tài)可用時就會返回义黎,用戶進(jìn)程再發(fā)起一次系統(tǒng)調(diào)用進(jìn)行數(shù)據(jù)讀取禾进。換句話說,就是NIO中N次的系統(tǒng)調(diào)用廉涕,借助Select泻云,只需要發(fā)起一次系統(tǒng)調(diào)用就夠了艇拍。其IO流程如下所示:


I/O Multiplexing

但是,select有一個限制宠纯,就是存在連接數(shù)限制卸夕,針對于此,又提出了poll婆瓜。其與select相比快集,主要是解決了連接限制。

select/epoll 雖然解決了NIO重復(fù)無效系統(tǒng)調(diào)用用的問題勃救,但同時又引入了新的問題碍讨。問題是:

  1. 用戶空間和內(nèi)核空間之間,大量的數(shù)據(jù)拷貝
  2. 內(nèi)核循環(huán)遍歷IO狀態(tài)蒙秒,浪費(fèi)CPU時間

換句話說勃黍,select/poll雖然減少了用戶進(jìn)程的發(fā)起的系統(tǒng)調(diào)用,但內(nèi)核的工作量只增不減晕讲。在高并發(fā)的情況下覆获,內(nèi)核的性能問題依舊。所以select/poll的問題本質(zhì)是:內(nèi)核存在無效的循環(huán)遍歷瓢省。

5.2. IO多路復(fù)用之epoll

針對select/pool引入的問題弄息,我們把解決問題的思路轉(zhuǎn)回到內(nèi)核上,如何減少內(nèi)核重復(fù)無效的循環(huán)遍歷呢勤婚?變主動為被動摹量,基于事件驅(qū)動來實(shí)現(xiàn)。其流程圖如下所示:

epoll

epoll相較于select/poll馒胆,多了兩次系統(tǒng)調(diào)用缨称,其中epoll_create建立與內(nèi)核的連接,epoll_ctl注冊事件祝迂,epoll_wait阻塞用戶進(jìn)程睦尽,等待IO事件。

select,poll,epoll

epoll型雳,已經(jīng)大大優(yōu)化了IO的執(zhí)行效率当凡,但在IO執(zhí)行的第一階段:數(shù)據(jù)準(zhǔn)備階段都還是被阻塞的。所以這是一個可以繼續(xù)優(yōu)化的點(diǎn)纠俭。

6. IO 模型之信號驅(qū)動IO(SIGIO)

信號驅(qū)動IO與BIO和NIO最大的區(qū)別就在于沿量,在IO執(zhí)行的數(shù)據(jù)準(zhǔn)備階段,不會阻塞用戶進(jìn)程冤荆。
如下圖所示:當(dāng)用戶進(jìn)程需要等待數(shù)據(jù)的時候朴则,會向內(nèi)核發(fā)送一個信號,告訴內(nèi)核我要什么數(shù)據(jù)匙赞,然后用戶進(jìn)程就繼續(xù)做別的事情去了佛掖,而當(dāng)內(nèi)核中的數(shù)據(jù)準(zhǔn)備好之后,內(nèi)核立馬發(fā)給用戶進(jìn)程一個信號涌庭,說”數(shù)據(jù)準(zhǔn)備好了芥被,快來查收“,用戶進(jìn)程收到信號之后坐榆,立馬調(diào)用recvfrom拴魄,去查收數(shù)據(jù)。

SIGIO

乍一看席镀,信號驅(qū)動式I/O模型有種異步操作的感覺匹中,但是在IO執(zhí)行的第二階段,也就是將數(shù)據(jù)從內(nèi)核空間復(fù)制到用戶空間這個階段豪诲,用戶進(jìn)程還是被阻塞的顶捷。

綜上,你會發(fā)現(xiàn)屎篱,不管是BIO還是NIO還是SIGIO服赎,它們最終都會被阻塞在IO執(zhí)行的第二階段。
那如果能將IO執(zhí)行的第二階段變成非阻塞交播,那就完美了重虑。

7. IO 模型之異步IO(AIO)

異步IO真正實(shí)現(xiàn)了IO全流程的非阻塞。用戶進(jìn)程發(fā)出系統(tǒng)調(diào)用后立即返回秦士,內(nèi)核等待數(shù)據(jù)準(zhǔn)備完成缺厉,然后將數(shù)據(jù)拷貝到用戶進(jìn)程緩沖區(qū),然后發(fā)送信號告訴用戶進(jìn)程IO操作執(zhí)行完畢(與SIGIO相比隧土,一個是發(fā)送信號告訴用戶進(jìn)程數(shù)據(jù)準(zhǔn)備完畢提针,一個是IO執(zhí)行完畢)。其流程如下:

AIO

所以次洼,之所以稱為異步IO关贵,取決于IO執(zhí)行的第二階段是否阻塞。因此前面講的BIO卖毁,NIO和SIGIO均為同步IO揖曾。

8. 總結(jié)

梳理完這些IO模型后,之前一直處于懵懂狀態(tài)的阻塞亥啦,非阻塞炭剪,同步異步IO,終于算是有個概念了翔脱。同時也糾正了自己一直以來的誤解奴拦,所以一路走來,愈發(fā)覺得返璞歸真的重要性届吁,只有如此错妖,才能在快速更迭的技術(shù)演進(jìn)中绿鸣,以不變應(yīng)萬變。

本片綜合多方資料寫就暂氯,難免紕漏潮模,但只有寫下來,才能得以指正痴施。所以擎厢,煩請各位看官不吝賜教。

參考資料:

  1. 程序員應(yīng)該這樣理解IO
  2. IO復(fù)用模型同步辣吃,異步动遭,阻塞,非阻塞及實(shí)例詳解
  3. 服務(wù)器網(wǎng)絡(luò)編程之 IO 模型
  4. http://www.c-jump.com/CIS77/CPU/VonNeumann/lecture.html
  5. 同步I/O(阻塞I/O神得,非阻塞I/O)厘惦,異步I/O
  6. 馬士兵:權(quán)威講解nio,epoll,多路復(fù)用
  7. Linux 內(nèi)核詳解以及內(nèi)核緩沖區(qū)技術(shù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市循头,隨后出現(xiàn)的幾起案子绵估,更是在濱河造成了極大的恐慌,老刑警劉巖卡骂,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件国裳,死亡現(xiàn)場離奇詭異,居然都是意外死亡全跨,警方通過查閱死者的電腦和手機(jī)缝左,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浓若,“玉大人渺杉,你說我怎么就攤上這事∨驳觯” “怎么了是越?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長碌上。 經(jīng)常有香客問我倚评,道長,這世上最難降的妖魔是什么馏予? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任天梧,我火速辦了婚禮,結(jié)果婚禮上霞丧,老公的妹妹穿的比我還像新娘呢岗。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布后豫。 她就那樣靜靜地躺著悉尾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挫酿。 梳的紋絲不亂的頭發(fā)上焕襟,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音饭豹,去河邊找鬼。 笑死务漩,一個胖子當(dāng)著我的面吹牛拄衰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饵骨,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼翘悉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了居触?” 一聲冷哼從身側(cè)響起妖混,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎轮洋,沒想到半個月后制市,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弊予,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年祥楣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汉柒。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡误褪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碾褂,到底是詐尸還是另有隱情兽间,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布正塌,位于F島的核電站嘀略,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏传货。R本人自食惡果不足惜屎鳍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望问裕。 院中可真熱鬧逮壁,春花似錦、人聲如沸粮宛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至忧饭,卻和暖如春扛伍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背词裤。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工刺洒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吼砂。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓逆航,卻偏偏與公主長得像,于是被迫代替她去往敵國和親渔肩。 傳聞我的和親對象是個殘疾皇子因俐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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