細說select、poll和epoll之間的區別與優缺點

I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。select,poll,epoll都是IO多路複用的機制。但select,poll,epoll本質上都是同步I/O,因爲他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而異步I/O則無需自己負責進行讀寫,異步I/O的實現會負責把數據從內核拷貝到用戶空間。下來,分別談談。

select——>

原理概述:

select 的核心功能是調用tcp文件系統的poll函數,不停的查詢,如果沒有想要的數據,主動執行一次調度(防止一直佔用cpu),直到有一個連接有想要的消息爲止。從這裏可以看出select的執行方式基本就是不同的調用poll,直到有需要的消息爲止。

缺點:

1、每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大;

2、同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大;

3、select支持的文件描述符數量太小了,默認是1024。

優點:

1、select的可移植性更好,在某些Unix系統上不支持poll()。

2、select對於超時值提供了更好的精度:微秒,而poll是毫秒。

poll——>

原理概述:

poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然後查詢每個fd對應的設備狀態,如果設備就緒則在設備等待隊列中加入一項並繼續遍歷,如果遍歷完所有fd後沒有發現就緒設備,則掛起當前進程,直到設備就緒或者主動超時,被喚醒後它又要再次遍歷fd。這個過程經歷了多次無謂的遍歷。poll還有一個特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd。

缺點:

1、大量的fd的數組被整體複製於用戶態和內核地址空間之間,而不管這樣的複製是不是有意義;

2、與select一樣,poll返回後,需要輪詢pollfd來獲取就緒的描述符。

優點:

1、poll() 不要求開發者計算最大文件描述符加一的大小。

2、poll() 在應付大數目的文件描述符的時候速度更快,相比於select。

3、它沒有最大連接數的限制,原因是它是基於鏈表來存儲的。

epoll——>

原理概述:

epoll同樣只告知那些就緒的文件描述符,而且當我們調用epoll_wait()獲得就緒文件描述符時, 返回的不是實際的描述符,而是一個代表就緒描述符數量的值,你只需要去epoll指定的一 個數組中依次取得相應數量的文件描述符即可,這裏也使用了內存映射技術,這 樣便徹底省掉了這些文件描述符在系統調用時複製的開銷。 

epoll的優點就是改進了前面所說缺點:

1、支持一個進程打開大數目的socket描述符:相比select,epoll則沒有對FD的限制,它所支持的FD上限是最大可以打開文件的數目,這個數字一般遠大於2048,舉個例子,在1GB內存的機器上大約是10萬左右,具體數目可以cat /proc/sys/fs/file-max察看,一般來說這個數目和系統內存關係很大。

2、IO效率不隨FD數目增加而線性下降:epoll不存在這個問題,它只會對"活躍"的socket進行操作--- 這是因爲在內核實現中epoll是根據每個fd上面的callback函數實現的。那麼,只有"活躍"的socket纔會主動的去調用 callback函數,其他idle狀態socket則不會,在這點上,epoll實現了一個"僞"AIO,因爲這時候推動力在os內核。在一些 benchmark中,如果所有的socket基本上都是活躍的---比如一個高速LAN環境,epoll並不比select/poll有什麼效率,相 反,如果過多使用epoll_ctl,效率相比還有稍微的下降。但是一旦使用idle connections模擬WAN環境,epoll的效率就遠在select/poll之上了。

3、使用mmap加速內核與用戶空間的消息傳遞:這點實際上涉及到epoll的具體實現了。無論是select,poll還是epoll都需要內核把FD消息通知給用戶空間,如何避免不必要的內存拷貝就 很重要,在這點上,epoll是通過內核於用戶空間mmap同一塊內存實現的。

三者對比與區別:

      1、select,poll實現需要自己不斷輪詢所有fd集合,直到設備就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調用epoll_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時,調用回調函數,把就緒fd放入就緒鏈表中,並喚醒在epoll_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select和poll在“醒着”的時候要遍歷整個fd集合,而epoll在“醒着”的時候只要判斷一下就緒鏈表是否爲空就行了,這節省了大量的CPU時間。這就是回調機制帶來的性能提升。

       2、select,poll每次調用都要把fd集合從用戶態往內核態拷貝一次,並且要把current往設備等待隊列中掛一次,而epoll只要一次拷貝,而且把current往等待隊列上掛也只掛一次(在epoll_wait的開始,注意這裏的等待隊列並不是設備等待隊列,只是一個epoll內部定義的等待隊列)。這也能節省不少的開銷。

wKiom1ecee_SajTcAABB7-ZTUR0253.png





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章