1. 程式人生 > 實用技巧 >select、poll和epoll之間的區別

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類,分別是writefds
    readfds、和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函式直到有就緒的檔案描述符立即返回給使用者態程序

  • 時間複雜度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()時便得到通知。