前兩篇文章介紹了select,poll,epoll的基本用法,如今咱們來看看它們的區別和適用場景。html
首先仍是來看常見的select和poll。對於網絡編程來講,通常認爲poll比select要高級一些,這主要源於如下幾個緣由:編程
固然也不是說select就沒有優勢:數組
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。