I/O複用機制概述

接下來咱們將介紹幾種常見的I/O模型及其區別java

  • blocking I/O
  • nonblocking I/O
  • I/O multiplexing (select and poll)
  • signal driven I/O (SIGIO)
  • asynchronous I/O (the POSIX aio_functions)

blocking I/Olinux

這個不用多解釋吧,阻塞套接字。下圖是它調用過程的圖示:web

I/O複用機制概述I/O複用機制概述

重點解釋下上圖,下面例子都會講到。首先application調用 recvfrom()轉入kernel,注意kernel有2個過程,wait for data和copy data from kernel to user。直到最後copy complete後,recvfrom()才返回。此過程一直是阻塞的。windows

nonblocking I/O:設計模式

與blocking I/O對立的,非阻塞套接字,調用過程圖以下:數組

I/O複用機制概述I/O複用機制概述

能夠看見,若是直接操做它,那就是個輪詢。。直到內核緩衝區有數據。瀏覽器

I/O multiplexing (select and poll)服務器

最多見的I/O複用模型,select。架構

I/O複用機制概述I/O複用機制概述

select先阻塞,有活動套接字才返回。與blocking I/O相比,select會有兩次系統調用,可是select能處理多個套接字。app

signal driven I/O (SIGIO)

只有UNIX系統支持,感興趣的課查閱相關資料

I/O複用機制概述I/O複用機制概述

I/O multiplexing (select and poll)相比,它的優點是,免去了select的阻塞與輪詢,當有活躍套接字時,由註冊的handler處理。

asynchronous I/O (the POSIX aio_functions)

不多有*nix系統支持,windows的IOCP則是此模型
I/O複用機制概述I/O複用機制概述

徹底異步的I/O複用機制,由於縱觀上面其它四種模型,至少都會在由kernel copy data to appliction時阻塞。而該模型是當copy完成後才通知application,可見是純異步的。好像只有windows的完成端口是這個模型,效率也很出色。

下面是以上五種模型的比較

I/O複用機制概述I/O複用機制概述

能夠看出,越日後,阻塞越少,理論上效率也是最優。5種模型的比較比較清晰了,剩下的就是把select,epoll,iocp,kqueue按號入座那就OK了。

select和iocp分別對應第3種與第5種模型,那麼epoll與kqueue呢?其實也於select屬於同一種模型,只是更高級一些,能夠看做有了第4種模型的某些特性,如callback機制。

那麼,爲何epoll,kqueue比select高級? 

答案是,他們無輪詢。由於他們用callback取代了。想一想看,當套接字比較多的時候,每次select()都要經過遍歷FD_SETSIZE個Socket來完成調度,無論哪一個Socket是活躍的,都遍歷一遍。這會浪費不少CPU時間。若是能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操做,那就避免了輪詢,這正是epoll與kqueue作的。

windows or *nix (IOCP or kqueue/epoll)?

誠然,Windows的IOCP很是出色,目前不多有支持asynchronous I/O的系統,可是因爲其系統自己的侷限性,大型服務器仍是在UNIX下。並且正如上面所述,kqueue/epoll 與 IOCP相比,就是多了一層從內核copy數據到應用層的阻塞,從而不能算做asynchronous I/O類。可是,這層小小的阻塞無足輕重,kqueue與epoll已經作得很優秀了。

提供一致的接口,IO Design Patterns

實際上,不論是哪一種模型,均可以抽象一層出來,提供一致的接口,廣爲人知的有ACE,Libevent這些,他們都是跨平臺的,並且他們自動選擇最優的I/O複用機制,用戶只需調用接口便可。說到這裏又得說說2個設計模式,Reactor and Proactor。Libevent是Reactor模型,ACE提供Proactor模型。實際都是對各類I/O複用機制的封裝。

Java nio包是什麼I/O機制?

我曾天真的認爲java nio封裝的是IOCP。。如今能夠肯定,目前的java本質是select()模型,能夠檢查/jre/bin/nio.dll得知。至於java服務器爲何效率還不錯。我也不得而知,多是設計得比較好吧。

對流行的IO模型進行簡單的比較

Select
1.Socket數量限制:該模式可操做的Socket數由FD_SETSIZE決定,內核默認32*32=1024.
2.操做限制:經過遍歷FD_SETSIZE個Socket來完成調度,無論哪一個Socket是活躍的,都遍歷一遍.

Poll
1.Socket數量幾乎無限制:該模式下的Socket對應的fd列表由一個數組來保存,大小不限(默認4k).
2.操做限制:同Select.

Epoll
1.Socket數量無限制:同Poll
2.操做無限制:基於內核提供的反射模式,有活躍Socket時,內核訪問該Socket的callback,不須要遍歷輪詢.

總結一些重點:

大部分狀況下,反射的效率都比遍從來的高,可是當全部Socket都活躍的時候,反射還會更高麼?這時候全部的callback都被喚醒,會致使資源的競爭.既然都是要處理全部的Socket,那麼遍歷是最簡單最有效的實現方式.

對於IM服務器,服務器和服務器之間都是長連接,但數量很少,通常一臺60\70個,好比採用ICE這種架構設計,但請求至關頻繁和密集,這時候經過反射喚醒callback不必定比用select去遍歷處理更好.對於web portal服務器,都是瀏覽器客戶端發起的http短連接請求,數量很大,好一點的網站動輒每分鐘上千個請求過來,同時服務器端還有更多的閒置等待超時的Socket,這時候不必把所有的Socket都遍歷處理,由於那些等待超時的請求是大多數的,這樣用Epoll會更好.

  1. 只有IOCP是asynchronous I/O,其餘機制或多或少都會有一點阻塞。
  2. select低效是由於每次它都須要輪詢。但低效也是相對的,視狀況而定,也可經過良好的設計改善
  3. epoll, kqueue是Reacor模式,IOCP是Proactor模式。
  4. java nio包是select模型。

免費提供最新Linux技術教程書籍,爲開源技術愛好者努力作得更多更好:http://www.linuxprobe.com/

相關文章
相關標籤/搜索