一道搜狗面試題:IO多路復用中select翩迈、poll、epoll之間的區(qū)別

原文:cnblogs.com/aspirant/p/9166944.html
作者:至尊寶

(1)select==>時間復雜度O(n)

它僅僅知道了盔夜,有I/O事件發(fā)生了负饲,卻并不知道是哪那幾個流(可能有一個堤魁,多個,甚至全部)返十,我們只能無差別輪詢所有流妥泉,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流洞坑,對他們進行操作盲链。所以select具有O(n)的無差別輪詢復雜度,同時處理的流越多迟杂,無差別輪詢時間就越長刽沾。

(2)poll==>時間復雜度O(n)

poll本質上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內核空間排拷,然后查詢每個fd對應的設備狀態(tài)侧漓, 但是它沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲的.

(3)epoll==>時間復雜度O(1)

epoll可以理解為event poll监氢,不同于忙輪詢和無差別輪詢火架,epoll會把哪個流發(fā)生了怎樣的I/O事件通知我們。所以我們說epoll實際上是事件驅動(每個事件關聯(lián)上fd)的忙菠,此時我們對這些流的操作都是有意義的何鸡。(復雜度降低到了O(1))

select,poll牛欢,epoll都是IO多路復用的機制骡男。I/O多路復用就通過一種機制,可以監(jiān)視多個描述符傍睹,一旦某個描述符就緒(一般是讀就緒或者寫就緒)隔盛,能夠通知程序進行相應的讀寫操作。但select拾稳,poll吮炕,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒后自己負責進行讀寫访得,也就是說這個讀寫過程是阻塞的龙亲,而異步I/O則無需自己負責進行讀寫,異步I/O的實現(xiàn)會負責把數(shù)據(jù)從內核拷貝到用戶空間悍抑。

epoll跟select都能提供多路I/O復用的解決方案鳄炉。在現(xiàn)在的Linux內核里有都能夠支持,其中epoll是Linux所特有搜骡,而select則應該是POSIX所規(guī)定拂盯,一般操作系統(tǒng)均有實現(xiàn)

select:

select本質上是通過設置或者檢查存放fd標志位的數(shù)據(jù)結構來進行下一步處理。這樣所帶來的缺點是:

1记靡、 單個進程可監(jiān)視的fd數(shù)量被限制谈竿,即能監(jiān)聽端口的大小有限团驱。

一般來說這個數(shù)目和系統(tǒng)內存關系很大,具體數(shù)目可以cat /proc/sys/fs/file-max察看空凸。32位機默認是1024個嚎花。64位機默認是2048.

2华坦、 對socket進行掃描時是線性掃描,即采用輪詢的方法潜慎,效率較低:

當套接字比較多的時候谦絮,每次select()都要通過遍歷FD_SETSIZE個Socket來完成調度,不管哪個Socket是活躍的,都遍歷一遍。這會浪費很多CPU時間肠套。如果能給套接字注冊某個回調函數(shù),當他們活躍時,自動完成相關操作憔辫,那就避免了輪詢,這正是epoll與kqueue做的仿荆。

3贰您、需要維護一個用來存放大量fd的數(shù)據(jù)結構,這樣會使得用戶空間和內核空間在傳遞該結構時復制開銷大

poll:

poll本質上和select沒有區(qū)別拢操,它將用戶傳入的數(shù)組拷貝到內核空間锦亦,然后查詢每個fd對應的設備狀態(tài),如果設備就緒則在設備等待隊列中加入一項并繼續(xù)遍歷令境,如果遍歷完所有fd后沒有發(fā)現(xiàn)就緒設備杠园,則掛起當前進程,直到設備就緒或者主動超時舔庶,被喚醒后它又要再次遍歷fd抛蚁。這個過程經歷了多次無謂的遍歷。

它沒有最大連接數(shù)的限制惕橙,原因是它是基于鏈表來存儲的瞧甩,但是同樣有一個缺點:

  • 大量的fd的數(shù)組被整體復制于用戶態(tài)和內核地址空間之間,而不管這樣的復制是不是有意義弥鹦。

  • poll還有一個特點是“水平觸發(fā)”肚逸,如果報告了fd后,沒有被處理彬坏,那么下次poll時會再次報告該fd吼虎。

epoll:

epoll有EPOLLLT和EPOLLET兩種觸發(fā)模式,LT是默認的模式苍鲜,ET是“高速”模式思灰。LT模式下,只要這個fd還有數(shù)據(jù)可讀混滔,每次 epoll_wait都會返回它的事件洒疚,提醒用戶程序去操作歹颓,而在ET(邊緣觸發(fā))模式中,它只會提示一次油湖,直到下次再有數(shù)據(jù)流入之前都不會再提示了巍扛,無 論fd中是否還有數(shù)據(jù)可讀。

所以在ET模式下乏德,read一個fd的時候一定要把它的buffer讀光撤奸,也就是說一直讀到read的返回值小于請求值,或者 遇到EAGAIN錯誤喊括。還有一個特點是胧瓜,epoll使用“事件”的就緒通知方式,通過epoll_ctl注冊fd郑什,一旦該fd就緒府喳,內核就會采用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知蘑拯。

epoll為什么要有EPOLLET觸發(fā)模式钝满?

如果采用EPOLLLT模式的話,系統(tǒng)中一旦有大量你不需要讀寫的就緒文件描述符申窘,它們每次調用epoll_wait都會返回弯蚜,這樣會大大降低處理程序檢索自己關心的就緒文件描述符的效率.。而采用EPOLLET這種邊沿觸發(fā)模式的話剃法,當被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時碎捺,epoll_wait()會通知處理程序去讀寫。

如果這次沒有把數(shù)據(jù)全部讀寫完(如讀寫緩沖區(qū)太小)玄窝,那么下次調用epoll_wait()時牵寺,它不會通知你,也就是它只會通知你一次恩脂,直到該文件描述符上出現(xiàn)第二次可讀寫事件才會通知你C泵ァ!俩块!這種模式比水平觸發(fā)效率高黎休,系統(tǒng)不會充斥大量你不關心的就緒文件描述符

epoll的優(yōu)點:

  • 沒有最大并發(fā)連接的限制,能打開的FD的上限遠大于1024(1G的內存上能監(jiān)聽約10萬個端口)玉凯;
  • 效率提升势腮,不是輪詢的方式,不會隨著FD數(shù)目的增加效率下降漫仆。只有活躍可用的FD才會調用callback函數(shù)捎拯;即Epoll最大的優(yōu)點就在于它只管你“活躍”的連接,而跟連接總數(shù)無關盲厌,因此在實際的網(wǎng)絡環(huán)境中署照,Epoll的效率就會遠遠高于select和poll祸泪。
  • 內存拷貝,利用mmap()文件映射內存加速與內核空間的消息傳遞建芙;即epoll使用mmap減少復制開銷没隘。

select、poll禁荸、epoll 區(qū)別總結:

1右蒲、支持一個進程所能打開的最大連接數(shù)

select

單個進程所能打開的最大連接數(shù)有FD_SETSIZE宏定義,其大小是32個整數(shù)的大懈鲜臁(在32位的機器上瑰妄,大小就是3232,同理64位機器上FD_SETSIZE為3264)钧大,當然我們可以對進行修改翰撑,然后重新編譯內核罩旋,但是性能可能會受到影響啊央,這需要進一步的測試。

poll

poll本質上和select沒有區(qū)別涨醋,但是它沒有最大連接數(shù)的限制瓜饥,原因是它是基于鏈表來存儲的

epoll

雖然連接數(shù)有上限,但是很大浴骂,1G內存的機器上可以打開10萬左右的連接乓土,2G內存的機器可以打開20萬左右的連接

2、FD劇增后帶來的IO效率問題

select

因為每次調用時都會對連接進行線性遍歷溯警,所以隨著FD的增加會造成遍歷速度慢的“線性下降性能問題”趣苏。

poll

同上

epoll

因為epoll內核中實現(xiàn)是根據(jù)每個fd上的callback函數(shù)來實現(xiàn)的,只有活躍的socket才會主動調用callback梯轻,所以在活躍socket較少的情況下食磕,使用epoll沒有前面兩者的線性下降的性能問題,但是所有socket都很活躍的情況下喳挑,可能會有性能問題彬伦。

3、 消息傳遞方式

select

內核需要將消息傳遞到用戶空間伊诵,都需要內核拷貝動作

poll

同上

epoll

epoll通過內核和用戶空間共享一塊內存來實現(xiàn)的单绑。

往期:100期面試題匯總

總結:

綜上,在選擇select曹宴,poll搂橙,epoll時要根據(jù)具體的使用場合以及這三種方式的自身特點。

1笛坦、表面上看epoll的性能最好区转,但是在連接數(shù)少并且連接都十分活躍的情況下唯袄,select和poll的性能可能比epoll好,畢竟epoll的通知機制需要很多函數(shù)回調蜗帜。

2恋拷、select低效是因為每次它都需要輪詢。但低效也是相對的厅缺,視情況而定蔬顾,也可通過良好的設計改善

今天對這三種IO多路復用進行對比,參考網(wǎng)上和書上面的資料湘捎,整理如下:

1诀豁、select實現(xiàn)

select的調用過程如下所示:

image
  • 使用copy_from_user從用戶空間拷貝fd_set到內核空間
  • 注冊回調函數(shù)__pollwait
  • 遍歷所有fd,調用其對應的poll方法(對于socket窥妇,這個poll方法是sock_poll舷胜,sock_poll根據(jù)情況會調用到tcp_poll,udp_poll或者datagram_poll) -以tcp_poll為例,其核心實現(xiàn)就是__pollwait活翩,也就是上面注冊的回調函數(shù)烹骨。
  • __pollwait的主要工作就是把current(當前進程)掛到設備的等待隊列中,不同的設備有不同的等待隊列材泄,對于tcp_poll來說沮焕,其等待隊列是sk->sk_sleep(注意把進程掛到等待隊列中并不代表進程已經睡眠了)。在設備收到一條消息(網(wǎng)絡設備)或填寫完文件數(shù)據(jù)(磁盤設備)后拉宗,會喚醒設備等待隊列上睡眠的進程峦树,這時current便被喚醒了。
  • poll方法返回時會返回一個描述讀寫操作是否就緒的mask掩碼旦事,根據(jù)這個mask掩碼給fd_set賦值魁巩。
  • 如果遍歷完所有的fd,還沒有返回一個可讀寫的mask掩碼姐浮,則會調用schedule_timeout是調用select的進程(也就是current)進入睡眠谷遂。當設備驅動發(fā)生自身資源可讀寫后,會喚醒其等待隊列上睡眠的進程单料。如果超過一定的超時時間(schedule_timeout指定)埋凯,還是沒人喚醒,則調用select的進程會重新被喚醒獲得CPU扫尖,進而重新遍歷fd白对,判斷有沒有就緒的fd。
  • 把fd_set從內核空間拷貝到用戶空間换怖。

往期:100期面試題匯總

總結:

select的幾大缺點:

  • 每次調用select甩恼,都需要把fd集合從用戶態(tài)拷貝到內核態(tài),這個開銷在fd很多時會很大
  • 同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大
  • select支持的文件描述符數(shù)量太小了条摸,默認是1024

2悦污、poll實現(xiàn)

poll的實現(xiàn)和select非常相似,只是描述fd集合的方式不同钉蒲,poll使用pollfd結構而不是select的fd_set結構切端,其他的都差不多,管理多個描述符也是進行輪詢,根據(jù)描述符的狀態(tài)進行處理顷啼,但是poll沒有最大文件描述符數(shù)量的限制踏枣。

poll和select同樣存在一個缺點就是,包含大量文件描述符的數(shù)組被整體復制于用戶態(tài)和內核的地址空間之間钙蒙,而不論這些文件描述符是否就緒茵瀑,它的開銷隨著文件描述符數(shù)量的增加而線性增大。

3躬厌、epoll

epoll既然是對select和poll的改進马昨,就應該能避免上述的三個缺點。那epoll都是怎么解決的呢扛施?在此之前鸿捧,我們先看一下epoll和select和poll的調用接口上的不同,select和poll都只提供了一個函數(shù)——select或者poll函數(shù)煮嫌。

而epoll提供了三個函數(shù)笛谦,epoll_create,epoll_ctl和epoll_wait抱虐,epoll_create是創(chuàng)建一個epoll句柄昌阿;epoll_ctl是注冊要監(jiān)聽的事件類型;epoll_wait則是等待事件的產生恳邀。

對于第一個缺點懦冰,epoll的解決方案在epoll_ctl函數(shù)中。每次注冊新的事件到epoll句柄中時(在epoll_ctl中指定EPOLL_CTL_ADD)谣沸,會把所有的fd拷貝進內核刷钢,而不是在epoll_wait的時候重復拷貝。epoll保證了每個fd在整個過程中只會拷貝一次乳附。

對于第二個缺點内地,epoll的解決方案不像select或poll一樣每次都把current輪流加入fd對應的設備等待隊列中,而只在epoll_ctl時把current掛一遍(這一遍必不可少)并為每個fd指定一個回調函數(shù)赋除,當設備就緒阱缓,喚醒等待隊列上的等待者時,就會調用這個回調函數(shù)举农,而這個回調函數(shù)會把就緒的fd加入一個就緒鏈表)荆针。epoll_wait的工作實際上就是在這個就緒鏈表中查看有沒有就緒的fd(利用schedule_timeout()實現(xiàn)睡一會,判斷一會的效果,和select實現(xiàn)中的第7步是類似的)航背。

對于第三個缺點喉悴,epoll沒有這個限制,它所支持的FD上限是最大可以打開文件的數(shù)目玖媚,這個數(shù)字一般遠大于2048,舉個例子,在1GB內存的機器上大約是10萬左右箕肃,具體數(shù)目可以cat /proc/sys/fs/file-max察看,一般來說這個數(shù)目和系統(tǒng)內存關系很大。

往期:100期面試題匯總

總結:

(1)select今魔,poll實現(xiàn)需要自己不斷輪詢所有fd集合突雪,直到設備就緒,期間可能要睡眠和喚醒多次交替涡贱。而epoll其實也需要調用epoll_wait不斷輪詢就緒鏈表咏删,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時问词,調用回調函數(shù)督函,把就緒fd放入就緒鏈表中,并喚醒在epoll_wait中進入睡眠的進程激挪。

雖然都要睡眠和交替辰狡,但是select和poll在“醒著”的時候要遍歷整個fd集合,而epoll在“醒著”的時候只要判斷一下就緒鏈表是否為空就行了垄分,這節(jié)省了大量的CPU時間宛篇。這就是回調機制帶來的性能提升。

(2)select薄湿,poll每次調用都要把fd集合從用戶態(tài)往內核態(tài)拷貝一次叫倍,并且要把current往設備等待隊列中掛一次,而epoll只要一次拷貝豺瘤,而且把current往等待隊列上掛也只掛一次(在epoll_wait的開始吆倦,注意這里的等待隊列并不是設備等待隊列,只是一個epoll內部定義的等待隊列)坐求。這也能節(jié)省不少的開銷蚕泽。

參考

https://www.cnblogs.com/zhaodahai/p/6831456.html

https://www.cnblogs.com/sky-heaven/p/7011684.html

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市桥嗤,隨后出現(xiàn)的幾起案子须妻,更是在濱河造成了極大的恐慌,老刑警劉巖泛领,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荒吏,死亡現(xiàn)場離奇詭異,居然都是意外死亡师逸,警方通過查閱死者的電腦和手機司倚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門豆混,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人动知,你說我怎么就攤上這事皿伺。” “怎么了盒粮?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵鸵鸥,是天一觀的道長。 經常有香客問我丹皱,道長妒穴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任摊崭,我火速辦了婚禮讼油,結果婚禮上,老公的妹妹穿的比我還像新娘呢簸。我一直安慰自己矮台,他們只是感情好,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布根时。 她就那樣靜靜地躺著瘦赫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蛤迎。 梳的紋絲不亂的頭發(fā)上确虱,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音替裆,去河邊找鬼校辩。 笑死,一個胖子當著我的面吹牛扎唾,可吹牛的內容都是我干的召川。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼胸遇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了汉形?” 一聲冷哼從身側響起纸镊,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎概疆,沒想到半個月后逗威,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡岔冀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年凯旭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡罐呼,死狀恐怖鞠柄,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情嫉柴,我是刑警寧澤厌杜,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站计螺,受9級特大地震影響夯尽,放射性物質發(fā)生泄漏。R本人自食惡果不足惜登馒,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一匙握、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陈轿,春花似錦肺孤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至法褥,卻和暖如春茫叭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背半等。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工揍愁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杀饵。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓莽囤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親切距。 傳聞我的和親對象是個殘疾皇子朽缎,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361