一、select機制
在linux下網絡通信中,經常用到select機制,這是一種異步通信的實現方式,select中提供一fd_set的數據結果,實際上是一個long類型的數組, 每一個數組元素都能與一打開的文件句柄建立聯系,通常這個句柄并不局限于網絡通信中的socket句柄,還包括其他文件、命名管道或設備句柄等。當程序中調用select()時,由內核根據IO狀態修改fd_set的內容,由此來通知執select()的進程哪一Socket或文件可讀或者可寫。
select的本質上是通過設置或者檢查存放fd標志位的數據結構來進行下一步處理。這樣所帶來的缺點是:
1、單個進程可監視的fd數量受到了限制,在32位機器上,他所能管理的fd數量最大為1024。
2、需要維護一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時復制開銷大。
3、對socket進行掃描時是線性掃描,當socket文件描述符數量變多時,大量的時間是被白白浪費掉的。
二、poll機制
poll是Linux中的字符設備驅動中有一個函數,Linux 2.5.44版本后已經被epoll所取代。poll機制是用在某些Unix系統中,使用poll()函數用于執行與select()函數同等功能的函數。
poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然后查詢每個fd對應的設備狀態,如果設備就緒則在設備等待隊列中加入一項并繼續遍歷,如果遍歷完所有fd后沒有發現就緒設備,則掛起當前進程,直到設備就緒或者主動超時,被喚醒后它又要再次遍歷fd。這個過程經歷了多次無謂的遍歷。
相比于select機制,poll機制采用鏈表來進行文件描述符的存儲,因此它并沒有最大連接數的限制,但同樣存在一些缺點:
1、大量的fd的數組被整體復制于用戶態和內核地址空間之間,而不管這樣的復制是不是有意義。
2、poll還有一個特點是“水平觸發”,如果報告了fd后,沒有被處理,那么下次poll時會再次報告該fd。
三、epoll機制
epoll是Linux內核為處理大批量的句柄而作了改進的poll,是Linux下多路復用IO接口select/poll的增強版本,它能顯著提高程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率。
epoll會復用文件描述符集合來傳遞結果而不用迫使開發者每次等待事件之前都必須重新準備要被偵聽的文件描述符集合,另一點原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入Ready隊列的描述符集合就行了。epoll除了提供select/poll那種IO事件的電平觸發(Level Triggered)外,還提供了邊沿觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提高應用程序效率。
相比于poll機制,epoll支持水平觸發和邊緣觸發,最大的特點在于邊緣觸發,它只告訴進程哪些fd剛剛變為就需態,并且只會通知一次。在fd的數組在用戶態和內核地址空間之間復制的問題上,epoll使用mmap減少復制開銷。還有一個特點是,epoll使用“事件”的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內核就會采用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知。
四、select、poll與epoll的比較
1、支持一個進程所能管理的最大連接數
select | 單個進程所能打開的最大連接數有FD_SETSIZE宏定義,其大小是32個整數的大小(在32位的機器上,大小就是32*32,同理64位機器上FD_SETSIZE為32*64),當然我們可以對進行修改,然后重新編譯內核,但是性能可能會受到影響,這需要進一步的測試。 |
poll | poll本質上和select沒有區別,但是它沒有最大連接數的限制,原因是它是基于鏈表來存儲的 |
epoll | 雖然連接數有上限,但是很大,1G內存的機器上可以打開10萬左右的連接,2G內存的機器可以打開20萬左右的連接 |
2、文件描述符劇增后帶來的IO效率問題
select | 因為每次調用時都會對連接進行線性遍歷,所以隨著FD的增加會造成遍歷速度慢的“線性下降性能問題”。 |
poll | 同上 |
epoll | 因為epoll內核中實現是根據每個fd上的callback函數來實現的,只有活躍的socket才會主動調用callback,所以在活躍socket較少的情況下,使用epoll沒有前面兩者的線性下降的性能問題,但是所有socket都很活躍的情況下,可能會有性能問題。 |
3、消息傳遞的方式
select | 內核需要將消息傳遞到用戶空間,都需要內核拷貝動作 |
poll | 同上 |
epoll | epoll通過內核和用戶空間共享一塊內存來實現的。 |
綜上,在選擇select,poll,epoll時要根據具體的使用場合以及這三種方式的自身特點,epoll的性能最好。但是考慮到在連接數少并且連接都十分活躍的情況下,select和poll的性能可能會比epoll更好,畢竟epoll的通知機制需要很多函數回調。
新聞熱點
疑難解答