IO基礎入門之I/O多路複用技術

轉載地址:http://my.oschina.net/fhd/blog/369064

在I/O編程過程中,當需要同時處理多個客戶端接入請求時,可以利用多線程或者I/O多路複用技術進行處理。I/O多路複用技術通過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單線程的情況下可以同時處理多個客戶端請求。與傳統的多線程/多進程模型比,I/O多路複用的最大優勢是系統開銷小,系統不需要創建新的額外進程或者線程,也不需要維護這些進程和線程的運行,降底了系統的維護工作量,節省了系統資源,I/O多路複用的主要應用場景如下:

  • 服務器需要同時處理多個處於監聽狀態或者多個連接狀態的套接字

  • 服務器需要同時處理多種網絡協議的套接字

目前支持I/O多路複用的系統調用有 selectpselectpollepoll,在Linux網絡編程過程中,很長一段時間都使用select做輪詢和網絡事件通知,然而select的一些固有缺陷導致了它的應用受到了很大的限制,最終Linux不得不在新的內核版本中尋找select的替代方案,最終選擇了epoll。epoll與select的原理比較類似,爲了克服select的缺點,epoll作了很多重大改進,現總結如下:

1. 支持一個進程打開的socket描述符(FD)不受限制(僅受限於操作系統的最大文件句柄數)

select最大的缺陷就是單個進程所打開的FD是有一定限制的,它由FD_SETSIZE設置,默認值是1024。對於那些需要支持上萬個TCP連接的大型服務器來說顯然太少了。可以選擇修改這個宏,然後重新編譯內核,不過這會帶來網絡效率的下降。我們也可以通過選擇多進程的方案(傳統的Apache方案)解決這個問題,不過雖然在Linux上創建進程的代價比較小,但仍舊是不可忽視的,另外,進程間的數據交換非常麻煩,對於Java由於沒有共享內存,需要通過Socket通信或者其他方式進行數據同步,這帶來了額外的性能損耗,增加了程序複雜度,所以也不是一種完美的解決方案。值得慶幸的是,epoll並沒有這個限制,它所支持的FD上限是操作系統的最大文件句柄數,這個數字遠遠大於1024。例如,在1GB內存的機器上大約是10萬個句柄左右,具體的值可以通過cat/proc/sys/fs/filemax察看,通常情況下這個值跟系統的內存關係比較大。

2. I/O效率不會隨着FD數目的增加而線性下降

傳統的select/poll另一個致命弱點就是當你擁有一個很大的socket集合,由於網絡延時或者鏈路空閒,任一時刻只有少部分的socket是“活躍”的,但是select/poll每次調用都會線性掃描全部集合,導致效率呈現線性下降。epoll不存在這個問題,它只會對“活躍”的socket進行操作-這是因爲在內核實現中epoll是根據每個fd上面的callback函數實現的,那麼,只有“活躍”的socket纔會主動的去調用callback函數,其他idle狀態socket則不會。在這點上,epoll實現了一個僞AIO。針對epoll和select性能對比的benchmark測試表明:如果所有的socket都處於活躍態。例如一個高速LAN環境,epoll並不比select/poll效率高太多;相反,如果過多使用epoll_ctl,效率相比還有稍微的下降。但是一旦使用idle connections模擬WAN環境,epoll的效率就遠在select/poll之上了。

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

無論是select,poll還是epoll都需要內核把FD消息通知給用戶空間,如何避免不必要的內存複製就顯得非常重要,epoll是通過內核和用戶空間mmap使用同一塊內存實現。

4. epoll的API更加簡單

用來克服select/poll缺點的方法不只有epoll,epoll只是一種Linux的實現方案。在freeBSD下有kqueue,而dev/poll是最古老的Solaris的方案,使用難度依次遞增。但epoll更加簡單。

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