IO多路復(fù)用之select顷牌、poll、epoll詳解
目前支持I/O多路復(fù)用的系統(tǒng)調(diào)用有select塞淹,pselect韧掩,poll,epoll窖铡,I/O多路復(fù)用就是通過(guò)一種機(jī)制,一個(gè)進(jìn)程可以監(jiān)視多個(gè)描述符坊谁,一旦某個(gè)描述符就緒(一般是讀就緒或者寫(xiě)就緒)费彼,能夠通知程序進(jìn)行相應(yīng)的讀寫(xiě)操作。但select口芍,pselect箍铲,poll,epoll本質(zhì)上都是同步I/O鬓椭,因?yàn)樗麄兌夹枰谧x寫(xiě)事件就緒后自己負(fù)責(zé)進(jìn)行讀寫(xiě)颠猴,也就是說(shuō)這個(gè)讀寫(xiě)過(guò)程是阻塞的,而異步I/O則無(wú)需自己負(fù)責(zé)進(jìn)行讀寫(xiě)小染,異步I/O的實(shí)現(xiàn)會(huì)負(fù)責(zé)把數(shù)據(jù)從內(nèi)核拷貝到用戶空間翘瓮。
與多進(jìn)程和多線程技術(shù)相比,I/O多路復(fù)用技術(shù)的最大優(yōu)勢(shì)是系統(tǒng)開(kāi)銷(xiāo)小裤翩,系統(tǒng)不必創(chuàng)建進(jìn)程/線程资盅,也不必維護(hù)這些進(jìn)程/線程,從而大大減小了系統(tǒng)的開(kāi)銷(xiāo)踊赠。
一呵扛、使用場(chǎng)景
IO多路復(fù)用是指內(nèi)核一旦發(fā)現(xiàn)進(jìn)程指定的一個(gè)或者多個(gè)IO條件準(zhǔn)備讀取,它就通知該進(jìn)程筐带。IO多路復(fù)用適用如下場(chǎng)合:
1)當(dāng)客戶處理多個(gè)描述符時(shí)(一般是交互式輸入和網(wǎng)絡(luò)套接口)今穿,必須使用I/O復(fù)用。
2)當(dāng)一個(gè)客戶同時(shí)處理多個(gè)套接口時(shí)伦籍,這種情況是可能的蓝晒,但很少出現(xiàn)。
3)如果一個(gè)TCP服務(wù)器既要處理監(jiān)聽(tīng)套接口鸽斟,又要處理已連接套接口拔创,一般也要用到I/O復(fù)用。
4)如果一個(gè)服務(wù)器即要處理TCP富蓄,又要處理UDP剩燥,一般要使用I/O復(fù)用。
5)如果一個(gè)服務(wù)器要處理多個(gè)服務(wù)或多個(gè)協(xié)議,一般要使用I/O復(fù)用灭红。
二侣滩、select、poll变擒、epoll簡(jiǎn)介
epoll跟select都能提供多路I/O復(fù)用的解決方案君珠。在現(xiàn)在的Linux內(nèi)核里有都能夠支持,其中epoll是Linux所特有娇斑,而select則應(yīng)該是POSIX所規(guī)定策添,一般操作系統(tǒng)均有實(shí)現(xiàn)。
1毫缆、select
基本原理:select 函數(shù)監(jiān)視的文件描述符分3類(lèi)唯竹,分別是writefds、readfds苦丁、和exceptfds浸颓。調(diào)用后select函數(shù)會(huì)阻塞,直到有描述符就緒(有數(shù)據(jù) 可讀旺拉、可寫(xiě)产上、或者有except),或者超時(shí)(timeout指定等待時(shí)間蛾狗,如果立即返回設(shè)為null即可)晋涣,函數(shù)返回。當(dāng)select函數(shù)返回后沉桌,可以通過(guò)遍歷fdset姻僧,來(lái)找到就緒的描述符。
基本流程蒲牧,如圖所示:
select目前幾乎在所有的平臺(tái)上支持撇贺,其良好跨平臺(tái)支持也是它的一個(gè)優(yōu)點(diǎn)。select的一個(gè)缺點(diǎn)在于單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制冰抢,在Linux上一般為1024松嘶,可以通過(guò)修改宏定義甚至重新編譯內(nèi)核的方式提升這一限制,但是這樣也會(huì)造成效率的降低挎扰。
select本質(zhì)上是通過(guò)設(shè)置或者檢查存放fd標(biāo)志位的數(shù)據(jù)結(jié)構(gòu)來(lái)進(jìn)行下一步處理翠订。這樣所帶來(lái)的缺點(diǎn)是:
1、select最大的缺陷就是單個(gè)進(jìn)程所打開(kāi)的FD是有一定限制的遵倦,它由FD_SETSIZE設(shè)置尽超,默認(rèn)值是1024。
一般來(lái)說(shuō)這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大梧躺,具體數(shù)目可以cat /proc/sys/fs/file-max察看似谁。32位機(jī)默認(rèn)是1024個(gè)傲绣。64位機(jī)默認(rèn)是2048.
2、對(duì)socket進(jìn)行掃描時(shí)是線性掃描巩踏,即采用輪詢的方法秃诵,效率較低。
當(dāng)套接字比較多的時(shí)候塞琼,每次select()都要通過(guò)遍歷FD_SETSIZE個(gè)Socket來(lái)完成調(diào)度菠净,不管哪個(gè)Socket是活躍的,都遍歷一遍彪杉。這會(huì)浪費(fèi)很多CPU時(shí)間毅往。如果能給套接字注冊(cè)某個(gè)回調(diào)函數(shù),當(dāng)他們活躍時(shí)派近,自動(dòng)完成相關(guān)操作煞抬,那就避免了輪詢,這正是epoll與kqueue做的构哺。
3、需要維護(hù)一個(gè)用來(lái)存放大量fd的數(shù)據(jù)結(jié)構(gòu)战坤,這樣會(huì)使得用戶空間和內(nèi)核空間在傳遞該結(jié)構(gòu)時(shí)復(fù)制開(kāi)銷(xiāo)大曙强。
2、poll
基本原理:poll本質(zhì)上和select沒(méi)有區(qū)別途茫,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間碟嘴,然后查詢每個(gè)fd對(duì)應(yīng)的設(shè)備狀態(tài),如果設(shè)備就緒則在設(shè)備等待隊(duì)列中加入一項(xiàng)并繼續(xù)遍歷囊卜,如果遍歷完所有fd后沒(méi)有發(fā)現(xiàn)就緒設(shè)備娜扇,則掛起當(dāng)前進(jìn)程,直到設(shè)備就緒或者主動(dòng)超時(shí)栅组,被喚醒后它又要再次遍歷fd雀瓢。這個(gè)過(guò)程經(jīng)歷了多次無(wú)謂的遍歷。
它沒(méi)有最大連接數(shù)的限制玉掸,原因是它是基于鏈表來(lái)存儲(chǔ)的刃麸,但是同樣有一個(gè)缺點(diǎn):
1)大量的fd的數(shù)組被整體復(fù)制于用戶態(tài)和內(nèi)核地址空間之間,而不管這樣的復(fù)制是不是有意義司浪。
2)poll還有一個(gè)特點(diǎn)是“水平觸發(fā)”泊业,如果報(bào)告了fd后,沒(méi)有被處理啊易,那么下次poll時(shí)會(huì)再次報(bào)告該fd吁伺。
注意:從上面看,select和poll都需要在返回后租谈,通過(guò)遍歷文件描述符來(lái)獲取已經(jīng)就緒的socket篮奄。事實(shí)上,同時(shí)連接的大量客戶端在一時(shí)刻可能只有很少的處于就緒狀態(tài),因此隨著監(jiān)視的描述符數(shù)量的增長(zhǎng)宦搬,其效率也會(huì)線性下降牙瓢。
3、epoll
epoll是在2.6內(nèi)核中提出的间校,是之前的select和poll的增強(qiáng)版本矾克。相對(duì)于select和poll來(lái)說(shuō),epoll更加靈活憔足,沒(méi)有描述符限制胁附。epoll使用一個(gè)文件描述符管理多個(gè)描述符,將用戶關(guān)系的文件描述符的事件存放到內(nèi)核的一個(gè)事件表中滓彰,這樣在用戶空間和內(nèi)核空間的copy只需一次控妻。
基本原理:epoll支持水平觸發(fā)和邊緣觸發(fā),最大的特點(diǎn)在于邊緣觸發(fā)揭绑,它只告訴進(jìn)程哪些fd剛剛變?yōu)榫途w態(tài)弓候,并且只會(huì)通知一次。還有一個(gè)特點(diǎn)是他匪,epoll使用“事件”的就緒通知方式菇存,通過(guò)epoll_ctl注冊(cè)fd,一旦該fd就緒邦蜜,內(nèi)核就會(huì)采用類(lèi)似callback的回調(diào)機(jī)制來(lái)激活該fd依鸥,epoll_wait便可以收到通知。
epoll的優(yōu)點(diǎn):
1悼沈、沒(méi)有最大并發(fā)連接的限制贱迟,能打開(kāi)的FD的上限遠(yuǎn)大于1024(1G的內(nèi)存上能監(jiān)聽(tīng)約10萬(wàn)個(gè)端口)。
2絮供、效率提升衣吠,不是輪詢的方式,不會(huì)隨著FD數(shù)目的增加效率下降壤靶。
只有活躍可用的FD才會(huì)調(diào)用callback函數(shù)蒸播;即Epoll最大的優(yōu)點(diǎn)就在于它只管你“活躍”的連接,而跟連接總數(shù)無(wú)關(guān)萍肆,因此在實(shí)際的網(wǎng)絡(luò)環(huán)境中袍榆,Epoll的效率就會(huì)遠(yuǎn)遠(yuǎn)高于select和poll。
3塘揣、內(nèi)存拷貝包雀,利用mmap()文件映射內(nèi)存加速與內(nèi)核空間的消息傳遞;即epoll使用mmap減少?gòu)?fù)制開(kāi)銷(xiāo)亲铡。
epoll對(duì)文件描述符的操作有兩種模式:LT(level trigger)和ET(edge trigger)才写。LT模式是默認(rèn)模式葡兑,LT模式與ET模式的區(qū)別如下:
LT模式:當(dāng)epoll_wait檢測(cè)到描述符事件發(fā)生并將此事件通知應(yīng)用程序,應(yīng)用程序可以不立即處理該事件赞草。下次調(diào)用epoll_wait時(shí)讹堤,會(huì)再次響應(yīng)應(yīng)用程序并通知此事件。
ET模式:當(dāng)epoll_wait檢測(cè)到描述符事件發(fā)生并將此事件通知應(yīng)用程序厨疙,應(yīng)用程序必須立即處理該事件洲守。如果不處理,下次調(diào)用epoll_wait時(shí)沾凄,不會(huì)再次響應(yīng)應(yīng)用程序并通知此事件梗醇。
1、LT模式
LT(level triggered)是缺省的工作方式撒蟀,并且同時(shí)支持block和no-block socket叙谨。在這種做法中,內(nèi)核告訴你一個(gè)文件描述符是否就緒了保屯,然后你可以對(duì)這個(gè)就緒的fd進(jìn)行IO操作手负。如果你不作任何操作,內(nèi)核還是會(huì)繼續(xù)通知你的姑尺。
2竟终、ET模式
ET(edge-triggered)是高速工作方式,只支持no-block socket股缸。在這種模式下,當(dāng)描述符從未就緒變?yōu)榫途w時(shí)吱雏,內(nèi)核通過(guò)epoll告訴你敦姻。然后它會(huì)假設(shè)你知道文件描述符已經(jīng)就緒,并且不會(huì)再為那個(gè)文件描述符發(fā)送更多的就緒通知歧杏,直到你做了某些操作導(dǎo)致那個(gè)文件描述符不再為就緒狀態(tài)了(比如镰惦,你在發(fā)送,接收或者接收請(qǐng)求犬绒,或者發(fā)送接收的數(shù)據(jù)少于一定量時(shí)導(dǎo)致了一個(gè)EWOULDBLOCK 錯(cuò)誤)旺入。但是請(qǐng)注意,如果一直不對(duì)這個(gè)fd作IO操作(從而導(dǎo)致它再次變成未就緒)凯力,內(nèi)核不會(huì)發(fā)送更多的通知(only once)茵瘾。
ET模式在很大程度上減少了epoll事件被重復(fù)觸發(fā)的次數(shù),因此效率要比LT模式高咐鹤。epoll工作在ET模式的時(shí)候拗秘,必須使用非阻塞套接口,以避免由于一個(gè)文件句柄的阻塞讀/阻塞寫(xiě)操作把處理多個(gè)文件描述符的任務(wù)餓死祈惶。
3雕旨、在select/poll中扮匠,進(jìn)程只有在調(diào)用一定的方法后,內(nèi)核才對(duì)所有監(jiān)視的文件描述符進(jìn)行掃描凡涩,而epoll事先通過(guò)epoll_ctl()來(lái)注冊(cè)一個(gè)文件描述符棒搜,一旦基于某個(gè)文件描述符就緒時(shí),內(nèi)核會(huì)采用類(lèi)似callback的回調(diào)機(jī)制活箕,迅速激活這個(gè)文件描述符力麸,當(dāng)進(jìn)程調(diào)用epoll_wait()時(shí)便得到通知。(此處去掉了遍歷文件描述符讹蘑,而是通過(guò)監(jiān)聽(tīng)回調(diào)的的機(jī)制末盔。這正是epoll的魅力所在。)
注意:如果沒(méi)有大量的idle-connection或者dead-connection座慰,epoll的效率并不會(huì)比select/poll高很多陨舱,但是當(dāng)遇到大量的idle-connection,就會(huì)發(fā)現(xiàn)epoll的效率大大高于select/poll版仔。
三游盲、select、poll蛮粮、epoll區(qū)別
1益缎、支持一個(gè)進(jìn)程所能打開(kāi)的最大連接數(shù)
2、FD劇增后帶來(lái)的IO效率問(wèn)題
3然想、消息傳遞方式
綜上莺奔,在選擇select,poll变泄,epoll時(shí)要根據(jù)具體的使用場(chǎng)合以及這三種方式的自身特點(diǎn):
1令哟、表面上看epoll的性能最好,但是在連接數(shù)少并且連接都十分活躍的情況下妨蛹,select和poll的性能可能比epoll好屏富,畢竟epoll的通知機(jī)制需要很多函數(shù)回調(diào)。
2蛙卤、select低效是因?yàn)槊看嗡夹枰喸兒莅搿5托б彩窍鄬?duì)的,視情況而定颤难,也可通過(guò)良好的設(shè)計(jì)改善神年。