IO多路復(fù)用

一拭嫁、簡(jiǎn)述

IO 多路復(fù)用是一種同步 IO 模型葱椭,實(shí)現(xiàn)一個(gè)線程可以監(jiān)視多個(gè)文件句柄鸿秆;一旦某個(gè)文件句柄就緒,就能夠通知應(yīng)用程序進(jìn)行相應(yīng)的讀寫操作帚稠;沒有文件句柄就緒時(shí)會(huì)阻塞應(yīng)用程序谣旁,交出 cpu。IO 是指網(wǎng)絡(luò) IO滋早,多路指多個(gè) TCP 連接(即 socket 或者 channel)榄审,復(fù)用指復(fù)用一個(gè)或幾個(gè)線程。意思說一個(gè)或一組線程處理多個(gè) TCP 連接杆麸。最大優(yōu)勢(shì)是減少系統(tǒng)開銷小搁进,不必創(chuàng)建過多的進(jìn)程/線程,也不必維護(hù)這些進(jìn)程/線程昔头。IO 多路復(fù)用的三種實(shí)現(xiàn)方式:select饼问、poll、epoll揭斧。

二莱革、select 機(jī)制

1??基本原理:
客戶端操作服務(wù)器時(shí)就會(huì)產(chǎn)生這三種文件描述符(簡(jiǎn)稱fd):writefds(寫)、readfds(讀)讹开、和 exceptfds(異常)盅视。select 會(huì)阻塞住監(jiān)視 3 類文件描述符,等有數(shù)據(jù)萧吠、可讀左冬、可寫、出異持叫停或超時(shí)就會(huì)返回;返回后通過遍歷 fdset 整個(gè)數(shù)組來找到就緒的描述符 fd,然后進(jìn)行對(duì)應(yīng)的 IO 操作狰腌。

2??優(yōu)點(diǎn):
幾乎在所有的平臺(tái)上支持除破,跨平臺(tái)支持性好

3??缺點(diǎn):

  1. 由于是采用輪詢方式全盤掃描,會(huì)隨著文件描述符 FD 數(shù)量增多而性能下降琼腔。
  2. 每次調(diào)用 select()瑰枫,都需要把 fd 集合從用戶態(tài)拷貝到內(nèi)核態(tài),并進(jìn)行遍歷(消息傳遞都是從內(nèi)核到用戶空間)丹莲。
  3. 單個(gè)進(jìn)程打開的 FD 是有限制(通過FD_SETSIZE設(shè)置)的光坝,默認(rèn)是 1024 個(gè),可修改宏定義甥材,但是效率仍然慢盯另。

三、poll 機(jī)制

1??基本原理與 select 一致洲赵,也是輪詢+遍歷鸳惯。唯一的區(qū)別就是 poll 沒有最大文件描述符限制(使用鏈表的方式存儲(chǔ) fd)。

2??poll 缺點(diǎn)

  1. 由于是采用輪詢方式全盤掃描叠萍,會(huì)隨著文件描述符 FD 數(shù)量增多而性能下降芝发。
  2. 每次調(diào)用 select(),都需要把 fd 集合從用戶態(tài)拷貝到內(nèi)核態(tài)苛谷,并進(jìn)行遍歷(消息傳遞都是從內(nèi)核到用戶空間)辅鲸。

四、epoll機(jī)制

1??基本原理:
沒有 fd 個(gè)數(shù)限制腹殿,用戶態(tài)拷貝到內(nèi)核態(tài)只需要一次独悴,使用時(shí)間通知機(jī)制來觸發(fā)。通過 epoll_ctl 注冊(cè) fd赫蛇,一旦 fd 就緒就會(huì)通過 callback 回調(diào)機(jī)制來激活對(duì)應(yīng) fd绵患,進(jìn)行相關(guān)的 io 操作。
epoll 之所以高性能是得益于它的三個(gè)函數(shù):

  1. epoll_create() 系統(tǒng)啟動(dòng)時(shí)悟耘,在 Linux 內(nèi)核里面申請(qǐng)一個(gè) B+樹結(jié)構(gòu)文件系統(tǒng)落蝙,返回 epoll 對(duì)象,也是一個(gè) fd暂幼。
  2. epoll_ctl() 每新建一個(gè)連接筏勒,都通過該函數(shù)操作 epoll 對(duì)象,在這個(gè)對(duì)象里面修改添加刪除對(duì)應(yīng)的鏈接 fd旺嬉,綁定一個(gè) callback 函數(shù)
  3. epoll_wait() 輪訓(xùn)所有的callback集合管行,并完成對(duì)應(yīng)的 IO 操作

2??優(yōu)點(diǎn):
沒 fd 這個(gè)限制,所支持的 FD 上限是操作系統(tǒng)的最大文件句柄數(shù)邪媳,1G 內(nèi)存大概支持 10 萬(wàn)個(gè)句柄捐顷。效率提高荡陷,使用回調(diào)通知而不是輪詢的方式,不會(huì)隨著 FD 數(shù)目的增加效率下降迅涮。內(nèi)核和用戶空間 mmap 同一塊內(nèi)存實(shí)現(xiàn)(mmap 是一種內(nèi)存映射文件的方法废赞,即將一個(gè)文件或者其它對(duì)象映射到進(jìn)程的地址空間)

3??epoll缺點(diǎn):
epoll 只能工作在 linux 下。

4??epoll 應(yīng)用:redis叮姑、nginx

五唉地、epoll 水平觸發(fā)(LT)與邊緣觸發(fā)(ET)的區(qū)別

epoll 有 epoll LT 和 epoll ET 兩種觸發(fā)模式,LT 是默認(rèn)的模式传透,ET 是“高速”模式耘沼。
1??LT 模式下,只要這個(gè) fd 還有數(shù)據(jù)可讀朱盐,每次 epoll_wait 都會(huì)返回它的事件群嗤,提醒用戶程序去操作
2??ET 模式下,它只會(huì)提示一次托享,直到下次再有數(shù)據(jù)流入之前都不會(huì)再提示了骚烧,無論 fd 中是否還有數(shù)據(jù)可讀。所以在 ET 模式下闰围,read 一個(gè) fd 的時(shí)候一定要把它的 buffer 讀完赃绊,或者遇到 EAGAIN 錯(cuò)誤。

六羡榴、select/poll/epoll之間的區(qū)別

七碧查、為什么有IO多路復(fù)用機(jī)制

沒有 IO 多路復(fù)用機(jī)制時(shí),有 BIO校仑、NIO 兩種實(shí)現(xiàn)方式忠售,但有一些問題。

1??同步阻塞(BIO)
服務(wù)端采用單線程迄沫,當(dāng) accept 一個(gè)請(qǐng)求后稻扬,在 recv 或 send 調(diào)用阻塞時(shí),將無法 accept 其他請(qǐng)求(必須等上一個(gè)請(qǐng)求 recv 或 send 完)羊瘩,無法處理并發(fā)泰佳。

服務(wù)器端采用多線程,當(dāng) accept 一個(gè)請(qǐng)求后尘吗,開啟線程進(jìn)行 recv逝她,可以完成并發(fā)處理,但隨著請(qǐng)求數(shù)增加需要增加系統(tǒng)線程睬捶,大量的線程占用很大的內(nèi)存空間黔宛,并且線程切換會(huì)帶來很大的開銷,10000 個(gè)線程真正發(fā)生讀寫事件的線程數(shù)不會(huì)超過 20%擒贸,每次 accept 都開一個(gè)線程也是一種資源浪費(fèi)臀晃。

2??同步非阻塞(NIO)
服務(wù)器端當(dāng) accept 一個(gè)請(qǐng)求后觉渴,加入 fds 集合,每次輪詢一遍 fds 集合 recv(非阻塞)數(shù)據(jù)积仗,沒有數(shù)據(jù)則立即返回錯(cuò)誤疆拘,每次輪詢所有 fd(包括沒有發(fā)生讀寫事件的fd)會(huì)很浪費(fèi) cpu蜕猫。

3??IO 多路復(fù)用
服務(wù)器端采用單線程通過 select/epoll 等系統(tǒng)調(diào)用獲取 fd 列表寂曹,遍歷有事件的 fd 進(jìn)行 accept/recv/send,使其能支持更多的并發(fā)連接請(qǐng)求回右。

八隆圆、理解 IO 多路復(fù)用機(jī)制

小王在 S 城開了一家快遞店,負(fù)責(zé)同城快送服務(wù)翔烁。小王因?yàn)橘Y金限制渺氧,雇傭了一批快遞員,然后小王發(fā)現(xiàn)資金不夠了蹬屹,只夠買一輛車送快遞侣背。

1??【經(jīng)營(yíng)方式一】
客戶每送來一份快遞,小王就讓一個(gè)快遞員盯著慨默,然后快遞員開車去送快遞贩耐。慢慢的小王就發(fā)現(xiàn)了這種經(jīng)營(yíng)方式存在下述問題:

  • 幾十個(gè)快遞員基本上時(shí)間都花在了搶車上了,大部分快遞員都處在閑置狀態(tài)厦取,誰(shuí)搶到了車潮太,誰(shuí)就能去送快遞。
  • 隨著快遞的增多虾攻,快遞員也越來越多铡买,小王發(fā)現(xiàn)快遞店里越來越擠,沒辦法雇傭新的快遞員了霎箍。
  • 快遞員之間的協(xié)調(diào)很費(fèi)時(shí)間奇钞。

2??【經(jīng)營(yíng)方式二】
小王只雇傭一個(gè)快遞員。然后呢漂坏,客戶送來的快遞景埃,小王按送達(dá)地點(diǎn)標(biāo)注好,然后依次放在一個(gè)地方樊拓。最后纠亚,那個(gè)快遞員依次去取快遞,一次拿一個(gè)筋夏,然后開著車去送快遞蒂胞,送好了就回來拿下一個(gè)快遞。

3??【對(duì)比】
兩種經(jīng)營(yíng)方式對(duì)比条篷,第二種明顯效率更高骗随,更好蛤织。在上述比喻中:

  • 每個(gè)快遞員------------------>每個(gè)線程
  • 每個(gè)快遞-------------------->每個(gè)socket(IO流)
  • 快遞的送達(dá)地點(diǎn)-------------->socket的不同狀態(tài)
  • 客戶送快遞請(qǐng)求-------------->來自客戶端的請(qǐng)求
  • 小王的經(jīng)營(yíng)方式-------------->服務(wù)端運(yùn)行的代碼
  • 一輛車---------------------->CPU的核數(shù)

4?? 于是有如下結(jié)論:

  1. 【經(jīng)營(yíng)方式一】就是傳統(tǒng)的并發(fā)模型,每個(gè) IO 流(快遞)都有一個(gè)新的線程(快遞員)管理鸿染。
  2. 【經(jīng)營(yíng)方式二】就是 IO 多路復(fù)用指蚜。只有單個(gè)線程(一個(gè)快遞員),通過跟蹤每個(gè) IO 流的狀態(tài)(每個(gè)快遞的送達(dá)地點(diǎn))涨椒,來管理多個(gè) IO 流摊鸡。

類比到真實(shí)的redis線程模型,如圖:

image

如圖蚕冬,簡(jiǎn)單來說免猾,就是 redis-client 在操作的時(shí)候,會(huì)產(chǎn)生具有不同事件類型的 socket囤热。在服務(wù)端猎提,有一段 IO 多路復(fù)用程序,將其置入隊(duì)列之中旁蔼。然后锨苏,文件事件分派器,依次去隊(duì)列中取棺聊,轉(zhuǎn)發(fā)到不同的事件處理器中伞租。需要說明的是,這個(gè) IO 多路復(fù)用機(jī)制躺屁,redis 還提供了 select肯夏、epoll、evport犀暑、kqueue 等多路復(fù)用函數(shù)庫(kù)驯击。

九、示例

100 萬(wàn)個(gè)連接耐亏,里面有 1 萬(wàn)個(gè)連接是活躍徊都,可以對(duì)比 select、poll广辰、epoll 的性能表現(xiàn):
1??select:不修改宏定義默認(rèn)是 1024暇矫,則需要100w/1024=977個(gè)進(jìn)程才可以支持 100 萬(wàn)連接,會(huì)使得 CPU 性能特別的差择吊。
2??poll:沒有最大文件描述符限制李根,100 萬(wàn)個(gè)鏈接則需要 100 萬(wàn)個(gè) fd,遍歷都響應(yīng)不過來了几睛,還有空間的拷貝消耗大量的資源房轿。
3??epoll:請(qǐng)求進(jìn)來時(shí)就創(chuàng)建 fd 并綁定一個(gè) callback,主需要遍歷 1 萬(wàn)個(gè)活躍連接的 callback 即可,即高效又不用內(nèi)存拷貝囱持。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末夯接,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子纷妆,更是在濱河造成了極大的恐慌盔几,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掩幢,死亡現(xiàn)場(chǎng)離奇詭異逊拍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)粒蜈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門顺献,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人枯怖,你說我怎么就攤上這事∧茉” “怎么了度硝?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)寿冕。 經(jīng)常有香客問我蕊程,道長(zhǎng),這世上最難降的妖魔是什么驼唱? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任藻茂,我火速辦了婚禮,結(jié)果婚禮上玫恳,老公的妹妹穿的比我還像新娘辨赐。我一直安慰自己,他們只是感情好京办,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布掀序。 她就那樣靜靜地躺著,像睡著了一般惭婿。 火紅的嫁衣襯著肌膚如雪不恭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天财饥,我揣著相機(jī)與錄音换吧,去河邊找鬼。 笑死钥星,一個(gè)胖子當(dāng)著我的面吹牛沾瓦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼暴拄,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼漓滔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起乖篷,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤响驴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后撕蔼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體豁鲤,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年鲸沮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了琳骡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讼溺,死狀恐怖楣号,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怒坯,我是刑警寧澤炫狱,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站剔猿,受9級(jí)特大地震影響视译,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜归敬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一酷含、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汪茧,春花似錦椅亚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至慌闭,卻和暖如春别威,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背驴剔。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工省古, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丧失。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓豺妓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子琳拭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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