select、poll和epoll之間的區別


在深入理解select、poll和epoll之間的區別之前,首先要了解什么是IO多路復用模型。

IO多路復用

簡單來說,IO多路復用是指內核一旦發現進程指定的一個或者多個IO條件准備就緒,它就通知該進程去進行IO操作。

詳細的描述可以參考IO模型。select、poll和epoll都是提供I/O多路復用的解決方案。

select

  • 函數
int select(int maxfdp, fd_set *readset, fd_set *writeset, 
            fd_set *exceptset, struct timeval *timeout);
  • 基本原理:select 函數監視的文件描述符分3類,分別是writefdsreadfds、和exceptfds。調用select時會被阻塞,直到有fd就緒(讀、寫、或者異常),或者超時(timeout指定等待時間,如果立即返回設為null即可)函數返回一個大於0的值,然后通過遍歷文件描述符集合fd_set,來找到就緒的描述符
  • 說明maxfdp是一個整數值,是指集合中所有文件描述符的范圍,即所有文件描述符的最大值加1。fd_set是以位圖的形式來存儲這些文件描述符。maxfdp也就是定義了位圖中有效地位的個數
  • 時間復雜度O(n)n為文件描述符集合fd_set的大小
  • 文件描述符最大限制1024

poll

  • 函數
int poll ( struct pollfd * fds, unsigned int nfds, int timeout);
  • 基本原理:和select 函數很相似,定義了一個struct pollfd結構類型的數組,用於存放需要檢測其狀態的所有文件描述符。調用poll函數之后,系統不會清空這個數組。特別是對於文件描述符比較多的情況下,在一定程度上可以提高處理的效率。這一點與select()函數不同,調用select()函數之后,select()函數會清空它所檢測的文件描述符集合,導致每次調用select()之前都必須把文件描述符重新加入到待檢測的集合中。因此,select()函數適合於只檢測一個文件描述符的情況,而poll()函數適合於大量文件描述符的情況
  • 時間復雜度O(n)n為文件描述符集合的大小
  • 文件描述符最大限制:無限制,fds是一個鏈表

epoll

  • 函數
// 建立一個epoll對象,參數size是內核保證能夠正確處理的最大句柄數
int epoll_create(int size);
// 操作上面建立的epoll
// 例如,將剛建立的socket加入到epoll中讓其監控,或者
// 把 epoll正在監控的某個socket句並移出epoll
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// 在指定的timeout時間內,當所有句柄中有事件發生時,就返回給用戶態的進程
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
  • 基本原理:將所有的文件描述符fd_set存儲在共享內存(用戶空間和內核空間都可以直接訪問)。調用epoll_create函數創建epoll對象,並以紅黑樹的結構存儲在內核空間,epoll_ctl函數用來在紅黑樹中添加或者注銷待監視文件描述符,最后調用epoll_wait函數直到有就緒的文件描述符立即返回給用戶態進程

epoll調用過程

  • 時間復雜度O(1)
  • 文件描述符最大限制:能打開的fd的上限遠大於10241G的內存上能監聽約10w+
epoll的兩種工作方式
  • 水平觸發(LT):若就緒的事件一次沒有處理完所有要做的事件,就會一直去處理。即就會將沒有處理完的事件繼續放回到就緒隊列之中(即那個內核中的鏈表),一直進行處理
  • 邊緣觸發(ET) :就緒的事件只能處理一次,若沒有處理完會在下次的其它事件就緒時再進行處理。而若以后再也沒有就緒的事件,那么剩余的那部分數據也會隨之而丟失。

ET模式的效率比LT模式的效率要高很多。只是如果使用ET模式,就要保證每次進行數據處理時,要將其處理完,不能造成數據丟失,這樣對編寫代碼的人要求就比較高。 為了保證數據的完整性,ET模式只支持非阻塞的讀寫。

select、poll和epoll對比

實現機制 時間復雜度 連接數 傳遞方式
select O(n) 1024 內核-->用戶
poll O(n) 無限制 內核-->用戶
epoll O(1) 很大 共享內存

在select和poll中,進程只有在調用方法后,內核才對所有監視的文件描述符進行掃描,發現有任何一個文件描述符就緒或者超時就立刻返回。epoll采用基於事件的就緒通知方式,事先通過epoll_ctl()來注冊一個文件描述符,一旦基於某個文件描述符就緒時,內核會采用類似callback的回調機制,迅速激活這個文件描述符,當進程調用epoll_wait()時便得到通知。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM