select,poll和epoll

在閱讀UNIX環境高級編程中,發現只寫了select和poll,關於epoll的回調機制還有所不理解。html

IO多路複用

首先要理解LINUX網絡IO多路複用,IO多路複用在Linux下包括了三種,select, poll, epoll,抽象來看,他們功能是相似的,但具體細節各有不一樣:首先都會對一組文件描述符進行相關事件的註冊,而後阻塞等待某些事件的發生或等待超時。更多細節詳見下面的 "具體怎麼用"。IO多路複用均可以關注多個文件描述符,但對於這三種機制而言,不一樣數量級文件描述符對性能的影響是不一樣的,下面會詳細介紹。linux

select

select將監聽的文件描述符分爲三組,每一組監聽不一樣的須要進行的IO操做。readfds是須要進行讀操做的文件描述符,writefds是須要進行寫操做的文件描述符,exceptfds是須要進行異常事件處理的文件描述符。這三個參數能夠用NULL來表示對應的事件不須要監聽。編程

當select返回時,每組文件描述符會被select過濾,只留下能夠進行對應IO操做的文件描述符。數組

  • linux 下 fd_set 是個 1024 位的位圖,每一個位表明一個 fd 的值,返回後須要掃描位圖,這也是效率低的緣由。性能問題且不提,正確性問題則更值得重視。由於這是一個 1024 位的位圖,所以當進程內的 fd 值 >= 1024 時,就會越界,可能會形成崩潰。對於服務器程序,fd >= 1024 很容易達到,只要鏈接數 + 打開的文件數足夠大便可發生。
  • 再來看fd_set結構體是怎麼記錄一批文件描述符是否有事件觸發的。仔細看fd_set結構的定義能夠發現,他實際上是一個__int32_t類型的數組,數組全部元素加起來共包含1024bit(由FD_SETSIZE定義)。記錄某個文件描述符是否觸發事件時,一個bit表明一個文件描述符的狀態,0表示沒有觸發事件,1表示觸發,把文件描述的數值映射爲下標,計算出哪一bit表明了這個文件描述符的狀態。
  • /* 其實就是建立了一個long int位圖數組,數組大小就是__FD_SETSIZE / __NFDBITS=64;
  1. 因此只能處理FD值小於1024的描述符,不然就數組越界 ,其行爲是未定義的*/

所以能夠看出,一旦文件描述符的數值超出1024,計算出的下標就有可能超出__int32_t數組的最大下標位置,因此有可能會出現數組越界的問題。服務器

poll

和select用三組文件描述符不一樣的是,poll只有一個pollfd數組,數組中的每一個元素都表示一個須要監聽IO操做事件的文件描述符。events參數是咱們須要關心的事件,revents是全部內核監測到的事件。網絡

  • Poll機制突破了Select機制中的文件描述符數量最大爲1024的限制。

epoll

epoll_create用於建立一個epoll實例,而epoll_ctl用於往epoll實例中增刪改要監測的文件描述符,epoll_wait則用於阻塞的等待能夠執行IO操做的文件描述符直到超時。性能

  • 添加到文件描述符上的實際都會與網卡創建回調機制,也就是實際發生時會自主調用一個回調方法,將事件所在的文件描述符插入到就緒隊列中
  • 引用程序調用epoll_wait 就能夠直接從就緒隊列中將全部就緒的文件描述符拿到,能夠說時間複雜度O(1)

關於上述的回調機制如何實現,還在查閱epoll相關源碼中線程

level-triggered and edge-triggered

狀態持續通知和狀態變化通知。unix

這兩個概念來自電路,triggered表明電路激活,也就是有事件通知給程序,level-triggered表示只要有IO操做能夠進行好比某個文件描述符有數據可讀,每次調用epoll_wait都會返回以通知程序能夠進行IO操做,edge-triggered表示只有在文件描述符狀態發生變化時,調用epoll_wait纔會返回,若是第一次沒有所有讀完該文件描述符的數據並且沒有新數據寫入,再次調用epoll_wait都不會有通知給到程序,由於文件描述符的狀態沒有變化。htm

select和poll都是狀態持續通知的機制,且不可改變,只要文件描述符中有IO操做能夠進行,那麼select和poll都會返回以通知程序。而epoll兩種通知機制可選。

不一樣IO多路複用方案優缺點

poll vs select

poll和select基本上是同樣的,poll相比select好在以下幾點:

  1. poll傳參對用戶更友好。好比不須要和select同樣計算不少奇怪的參數好比nfds(值最大的文件描述符+1),再好比不須要分開三組傳入參數。
  2. poll會比select性能稍好些,由於select是每一個bit位都檢測,假設有個值爲1000的文件描述符,select會從第一位開始檢測一直到第1000個bit位。但poll檢測的是一個數組。
  3. select的時間參數在返回的時候各個系統的處理方式不統一,若是但願程序可移植性更好,須要每次調用select都初始化時間參數。

select比poll好在下面幾點

  1. 支持select的系統更多,兼容更強大,有一些unix系統不支持poll
  2. select提供精度更高(到microsecond)的超時時間,而poll只提供到毫秒的精度。

但整體而言 select和poll基本一致。

epoll vs poll&select

epoll優於select&poll在下面幾點:

  1. 在須要同時監聽的文件描述符數量增長時,select&poll是O(N)的複雜度,epoll是O(1),在N很小的狀況下,差距不會特別大,但若是N很大的前提下,一次O(N)的循環可要比O(1)慢不少,因此高性能的網絡服務器都會選擇epoll進行IO多路複用。
  2. epoll內部用一個文件描述符掛載須要監聽的文件描述符,這個epoll的文件描述符能夠在多個線程/進程共享,因此epoll的使用場景要比select&poll要多。

參考

https://zhuanlan.zhihu.com/p/...
https://www.jianshu.com/p/019...
https://www.cnblogs.com/Anker...
https://www.cnblogs.com/anker...

相關文章
相關標籤/搜索