雲栖号資訊:【 點選檢視更多行業資訊】
在這裡您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!
select,poll和epoll其實都是作業系統中IO多路複用實作的方法。
select
select方法本質其實就是維護了一個檔案描述符(fd)數組,以此為基礎,實作IO多路複用的功能。這個fd數組有長度限制,在32位系統中,最大值為1024個,而在64位系統中,最大值為2048個,這個配置可以調用

來檢視
select方法被調用,首先需要将fd_set從使用者空間拷貝到核心空間,然後核心用poll機制(此poll機制非IO多路複用的那個poll方法,可參加附錄)直到有一個fd活躍,或者逾時了,方法傳回。
int select(int maxfdpl, fd_set readfds, fd_set writefds, fd_set exceptfds, struct timeval timeout);
- 如果傳回值為-1,表明發生了錯誤
- 如果傳回值為0,表明逾時了
- 如果傳回值為正數,表明有n個fd準備就緒了
select方法傳回後,需要輪詢fd_set,以檢查出發生IO事件的fd。這樣一套下來,select方法的缺點就很明顯了:
- fd_set在使用者空間和核心空間的頻繁複制,效率低
- 單個程序可監控的fd數量有限制,無論是1024還是2048,對于很多情景來說都是不夠用的。
- 基于輪詢來實作,效率低
poll
poll本質上和select沒有差別,依然需要進行資料結構的複制,依然是基于輪詢來實作,但差別就是,select使用的是fd數組,而poll則是維護了一個連結清單,是以從理論上,poll方法中,單個程序能監聽的fd不再有數量限制。但是輪詢,複制等select存在的問題,poll依然存在
epoll
epoll就是對select和poll的改進了。它的核心思想是基于事件驅動來實作的,實作起來也并不難,就是給每個fd注冊一個回調函數,當fd對應的裝置發生IO事件時,就會調用這個回調函數,将該fd放到一個連結清單中,然後由用戶端從該連結清單中取出一個個fd,以此達到O(1)的時間複雜度
epoll操作實際上對應着有三個函數:epoll_create,epoll_ctr,epoll_wait
epoll_create
epoll_create相當于在核心中建立一個存放fd的資料結構。在select和poll方法中,核心都沒有為fd準備存放其的資料結構,隻是簡單粗暴地把數組或者連結清單複制進來;而epoll則不一樣,epoll_create會在核心建立一顆專門用來存放fd結點的紅黑樹,後續如果有新增的fd結點,都會注冊到這個epoll紅黑樹上。
epoll_ctr
另一點不一樣的是,select和poll會一次性将監聽的所有fd都複制到核心中,而epoll不一樣,當需要添加一個新的fd時,會調用epoll_ctr,給這個fd注冊一個回調函數,然後将該fd結點注冊到核心中的紅黑樹中。當該fd對應的裝置活躍時,會調用該fd上的回調函數,将該結點存放在一個就緒連結清單中。這也解決了在核心空間和使用者空間之間進行來回複制的問題。
epoll_wait
epoll_wait的做法也很簡單,其實直接就是從就緒連結清單中取結點,這也解決了輪詢的問題,時間複雜度變成O(1)
是以綜合來說,epoll的優點有:
- 沒有最大并發連接配接的限制,遠遠比1024或者2048要大。(江湖傳言1G的記憶體上能監聽10W個端口)
- 效率變高。epoll是基于事件驅動實作的,不會随着fd數量上升而效率下降
- 減少記憶體拷貝的次數
水準觸發和邊緣觸發
簡單了解下
水準觸發的意思就是說,隻要條件滿足,對應的事件就會一直被觸發。是以如果條件滿足了但未進行處理,那麼就會一直被通知
邊緣觸發的意思就是說,條件滿足後,對應的事件隻會被觸發一次,無論是否被處理,都隻會觸發一次。
而對于select和poll來說,其觸發都是水準觸發。而epoll則有兩種模式:·EPOLLLT和EPOLLET
- EPOLLLT(預設狀态):也就是水準觸發。在該模式下,隻要這個fd還有資料可讀,那麼epoll_wait函數就會傳回該fd
- EPOLLET(高速模式):也就是邊緣觸發。在該模式下,當被監控的fd上有可讀寫事件發生時,epoll_wait會通知程式去讀寫,若本次讀寫沒有讀完所有資料,或者甚至沒有進行處理,那麼下一次調用epoll_wait時,也不會擷取到該fd。這種效率比水準觸發的要高,系統中不會充斥着大量程式不感興趣的fd,不感興趣直接忽視就行,下次不會再觸發
總結:
- select,poll是基于輪詢實作的,将fd_set從使用者空間複制到核心空間,然後讓核心空間以poll機制來進行輪詢,一旦有其中一個fd對應的裝置活躍了,那麼就把整個fd_set傳回給用戶端(複制到使用者空間),再由用戶端來輪詢每個fd的,找出發生了IO事件的fd
- epoll是基于事件驅動實作的,加入一個新的fd,會調用epoll_ctr函數為該fd注冊一個回調函數,然後将該fd結點注冊到核心中的epoll紅黑樹中,當IO事件發生時,就會調用回調函數,将該fd結點放到就緒連結清單中,epoll_wait函數實際上就是從這個就緒連結清單中擷取這些fd。
- epoll分為EPOLLLT(水準觸發,預設狀态)和EPOLLET(邊緣觸發,效率高)
- 并不是所有的情況中epoll都是最好的,比如當fd數量比較小的時候,epoll不見得就一定比select和poll好
【雲栖号線上課堂】每天都有産品技術專家分享!
課程位址:
https://yqh.aliyun.com/live立即加入社群,與專家面對面,及時了解課程最新動态!
【雲栖号線上課堂 社群】
https://c.tb.cn/F3.Z8gvnK
原文釋出時間:2020-05-30
本文作者:JAYICE
本文來自:“
掘金”,了解相關資訊可以關注“掘金”