select/poll/epoll 對比

前兩篇文章介紹了select,poll,epoll的基本用法,如今咱們來看看它們的區別和適用場景。html

首先仍是來看常見的select和poll。對於網絡編程來講,通常認爲poll比select要高級一些,這主要源於如下幾個緣由:編程

  1. poll() 不要求開發者計算最大文件描述符加一的大小。
  2. poll() 在應付大數目的文件描述符的時候速度更快,由於對於select()來講內核須要檢查大量描述符對應的fd_set 中的每個比特位,比較費時。
  3. select 能夠監控的文件描述符數目是固定的,相對來講也較少(1024或2048),若是須要監控數值比較大的文件描述符,就算所監控的描述符不多,若是分佈的很稀疏也會效率很低,對於poll() 函數來講,就能夠建立特定大小的數組來保存監控的描述符,而不受文件描述符值大小的影響,並且poll()能夠監控的文件數目遠大於select。
  4. 對於select來講,所監控的fd_set在select返回以後會發生變化,因此在下一次進入select()以前都須要從新初始化須要監控的fd_set,poll() 函數將監控的輸入和輸出事件分開,容許被監控的文件數組被複用而不須要從新初始化。
  5. select() 函數的超時參數在返回時也是未定義的,考慮到可移植性,每次在超時以後在下一次進入到select以前都須要從新設置超時參數。

  固然也不是說select就沒有優勢:數組

  1. select()的可移植性更好,在某些Unix系統上不支持poll()
  2. select() 對於超時值提供了更好的精度:微秒,而poll是毫秒。

epoll的優勢:服務器

1.支持一個進程打開大數目的socket描述符(FD)網絡

  select 最不能忍受的是一個進程所打開的FD是有必定限制的,由FD_SETSIZE設置,默認值是1024/2048。對於那些須要支持的上萬鏈接數目的IM服務器來講顯然太少了。這時候你一是能夠選擇修改這個宏而後從新編譯內核。不過 epoll則沒有這個限制,它所支持的FD上限是最大能夠打開文件的數目,這個數字通常遠大於2048,舉個例子,在1GB內存的機器上大約是10萬左右,具體數目能夠cat /proc/sys/fs/file-max察看,通常來講這個數目和系統內存關係很大。socket

2.IO效率不隨FD數目增長而線性降低函數

  傳統的select/poll另外一個致命弱點就是當你擁有一個很大的socket集合,不過因爲網絡延時,任一時間只有部分的socket是"活躍"的,可是select/poll每次調用都會線性掃描所有的集合,致使效率呈現線性降低。可是epoll不存在這個問題,它只會對"活躍"的socket進行操做---這是由於在內核實現中epoll是根據每一個fd上面的callback函數實現的。那麼,只有"活躍"的socket纔會主動的去調用 callback函數,其餘idle狀態socket則不會,在這點上,epoll實現了一個"僞"AIO,由於這時候推進力在Linux內核。htm

3.使用mmap加速內核與用戶空間的消息傳遞。blog

  這點實際上涉及到epoll的具體實現了。不管是select,poll仍是epoll都須要內核把FD消息通知給用戶空間,如何避免沒必要要的內存拷貝就很重要,在這點上,epoll是經過內核與用戶空間mmap同一塊內存實現的。 隊列

  對於poll來講須要將用戶傳入的 pollfd 數組拷貝到內核空間,由於拷貝操做和數組長度相關,時間上這是一個O(n)操做,當事件發生,poll返回將得到的數據傳送到用戶空間並執行釋放內存和剝離等待隊列等善後工做,向用戶空間拷貝數據與剝離等待隊列等操做的的時間複雜度一樣是O(n)。

 

  這兩天看到一個雲風他們那裏的bug就是由於使用的開源庫中做者使用了非阻塞connect使用select() 來等待超時,可是並未檢查FD_SETSIZE,當文件描述符數目大於這個數目以後就會出現內存越界錯誤,形成coredump。

相關文章
相關標籤/搜索