select,poll,epoll的归纳总结区分
以下資料都是來自網(wǎng)上搜集整理。引用源詳見文章末尾。
1 Select、Poll與Epoll簡介
| Select | select本質(zhì)上是通過設(shè)置或者檢查存放fd標(biāo)志位的數(shù)據(jù)結(jié)構(gòu)來進(jìn)行下一步處理。這樣所帶來的缺點(diǎn)是: 1 單個(gè)進(jìn)程可監(jiān)視的fd數(shù)量被限制 2 需要維護(hù)一個(gè)用來存放大量fd的數(shù)據(jù)結(jié)構(gòu),這樣會(huì)使得用戶空間和內(nèi)核空間在傳遞該結(jié)構(gòu)時(shí)復(fù)制開銷大 3 對socket進(jìn)行掃描時(shí)是線性掃描 |
| Poll | poll本質(zhì)上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間,然后查詢每個(gè)fd對應(yīng)的設(shè)備狀態(tài),如果設(shè)備就緒則在設(shè)備等待隊(duì)列中加入一項(xiàng)并繼續(xù)遍歷,如果遍歷完所有fd后沒有發(fā)現(xiàn)就緒設(shè)備,則掛起當(dāng)前進(jìn)程,直到設(shè)備就緒或者主動(dòng)超時(shí),被喚醒后它又要再次遍歷fd。這個(gè)過程經(jīng)歷了多次無謂的遍歷。 它沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲(chǔ)的,但是同樣有一個(gè)缺點(diǎn):大量的fd的數(shù)組被整體復(fù)制于用戶態(tài)和內(nèi)核地址空間之間,而不管這樣的復(fù)制是不是有意義。 poll還有一個(gè)特點(diǎn)是“水平觸發(fā)”,如果報(bào)告了fd后,沒有被處理,那么下次poll時(shí)會(huì)再次報(bào)告該fd。 |
| Epoll | epoll支持水平觸發(fā)和邊緣觸發(fā),最大的特點(diǎn)在于邊緣觸發(fā),它只告訴進(jìn)程哪些fd剛剛變?yōu)榫托钁B(tài),并且只會(huì)通知一次。 在前面說到的復(fù)制問題上,epoll使用mmap減少復(fù)制開銷。 還有一個(gè)特點(diǎn)是,epoll使用“事件”的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內(nèi)核就會(huì)采用類似callback的回調(diào)機(jī)制來激活該fd,epoll_wait便可以收到通知 |
注:水平觸發(fā)(level-triggered)——只要滿足條件,就觸發(fā)一個(gè)事件(只要有數(shù)據(jù)沒有被獲取,內(nèi)核就不斷通知你);邊緣觸發(fā)(edge-triggered)——每當(dāng)狀態(tài)變化時(shí),觸發(fā)一個(gè)事件。
2 Select、Poll與Epoll區(qū)別
| Select | Poll | Epoll | |
| 支持最大連接數(shù) | 1024(x86) or 2048(x64) | 無上限 | 無上限 |
| IO效率 | 每次調(diào)用進(jìn)行線性遍歷,時(shí)間復(fù)雜度為O(N) | 每次調(diào)用進(jìn)行線性遍歷,時(shí)間復(fù)雜度為O(N) | 使用“事件”通知方式,每當(dāng)fd就緒,系統(tǒng)注冊的回調(diào)函數(shù)就會(huì)被調(diào)用,將就緒fd放到rdllist里面,這樣epoll_wait返回的時(shí)候我們就拿到了就緒的fd。時(shí)間發(fā)復(fù)雜度O(1) |
| fd拷貝 | 每次select都拷貝 | 每次poll都拷貝 | 調(diào)用epoll_ctl時(shí)拷貝進(jìn)內(nèi)核并由內(nèi)核保存,之后每次epoll_wait不拷貝 |
3 性能比較
由于博主并沒有提供測試的機(jī)器參數(shù),以及測試程序代碼,所以這個(gè)性能測試只能夠算是一個(gè)補(bǔ)充吧,對于epoll在大量fd情況下優(yōu)勢的直觀展示。
表格左側(cè)是描述符集合的大小,右側(cè)分別表示1s對poll和epoll的調(diào)用次數(shù),也就是性能瓶頸。
從上表可以看出當(dāng)fd數(shù)量較少的時(shí)候poll略優(yōu)于epoll,但是當(dāng)fd增大到某個(gè)閾值時(shí),poll性能急劇下降。而epoll始終保持的穩(wěn)定的性能。
4 使用
當(dāng)同事需要保持很多的長連接,而且連接的開關(guān)很頻繁時(shí),就能夠發(fā)揮epoll最大的優(yōu)勢了。這里與服務(wù)器模型其實(shí)已經(jīng)有些交集了。
同時(shí)需要保持很多的長連接,而且連接的開關(guān)很頻繁,最高效的模型是非阻塞、異步IO模型。而且不要用select/poll,這兩個(gè)API的有著O(N)的時(shí)間復(fù)雜度。在Linux用epoll,BSD用kqueue,Windows用IOCP,或者用libevent封裝的統(tǒng)一接口(對于不同平臺(tái)libevent實(shí)現(xiàn)時(shí)采用各個(gè)平臺(tái)特有的API),這些平臺(tái)特有的API時(shí)間復(fù)雜度為O(1)。 然而在非阻塞,異步I/O模型下的編程是非常痛苦的。由于I/O操作不再阻塞,報(bào)文的解析需要小心翼翼,并且需要親自管理維護(hù)每個(gè)鏈接的狀態(tài)。并且為了充分利用CPU,還應(yīng)結(jié)合線程池,避免在輪詢線程中處理業(yè)務(wù)邏輯。
但這種模型的效率是極高的。以知名的http服務(wù)器nginx為例,可以輕松應(yīng)付上千萬的空連接+少量活動(dòng)鏈接,每個(gè)連接連接僅需要幾K的內(nèi)核緩沖區(qū),想要應(yīng)付更多的空連接,只需簡單的增加內(nèi)存(數(shù)據(jù)來源為淘寶一位工程師的一次技術(shù)講座,并未實(shí)測)。這使得DDoS攻擊者的成本大大增加,這種模型攻擊者只能將服務(wù)器的帶寬全部占用,才能達(dá)到目的,而兩方的投入是不成比例的。
注:長連接——連接后始終不斷開,然后進(jìn)行報(bào)文發(fā)送和接受;短鏈接——每一次通訊都建立連接,通訊完成即斷開連接,下次通訊再建立連接。
總結(jié)
以上是生活随笔為你收集整理的select,poll,epoll的归纳总结区分的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SSH-CLIENT : gSTM
- 下一篇: 第十一章 图形视图、动画、状态机框架