首先,介紹幾種常見的I/O模型及其區(qū)別,如下:
blocking I/O
重 點解釋下上圖,下面例子都會講到。首先application調(diào)用 recvfrom()轉(zhuǎn)入kernel,注意kernel有2個過程,wait for data和copy data from kernel to user。直到最后copy complete后,recvfrom()才返回。此過程一直是阻塞的。 nonblocking I/O:
可以看見,如果直接操作它,那就是個輪詢。。直到內(nèi)核緩沖區(qū)有數(shù)據(jù)。 I/O multiplexing (select and poll)
select先阻塞,有活動套接字才返回。與blocking I/O相比,select會有兩次系統(tǒng)調(diào)用,但是select能處理多個套接字。 signal driven I/O (SIGIO)
與I/O multiplexing (select and poll)相比,它的優(yōu)勢是,免去了select的阻塞與輪詢,當有活躍套接字時,由注冊的handler處理。 asynchronous I/O (the POSIX aio_functions)
完全異步的I/O復用機制,因為縱觀上面其它四種模型,至少都會在由kernel copy data to appliction時阻塞。而該模型是當copy完成后才通知application,可見是純異步的。好像只有windows的完成端口是這個模型,效率也很出色。 下面是以上五種模型的比較
可以看出,越往后,阻塞越少,理論上效率也是最優(yōu)。 =====================分割線================================== 5種模型的比較比較清晰了,剩下的就是把select,epoll,iocp,kqueue按號入座那就OK了。 select和iocp分別對應第3種與第5種模型,那么epoll與kqueue呢?其實也于select屬于同一種模型,只是更高級一些,可以看作有了第4種模型的某些特性,如callback機制。 那么,為什么epoll,kqueue比select高級? 答案是,他們無輪詢。 因為他們用callback取代了。想想看,當套接字比較多的時候,每次select()都要通過遍歷FD_SETSIZE個Socket來完成調(diào)度,不 管哪個Socket是活躍的,都遍歷一遍。這會浪費很多CPU時間。如果能給套接字注冊某個回調(diào)函數(shù),當他們活躍時,自動完成相關(guān)操作,那就避免了輪詢, 這正是epoll與kqueue做的。 windows or *nix (IOCP or kqueue/epoll)? 誠然,Windows的IOCP非常出色,目前很少有支持asynchronous I/O的系統(tǒng),但是由于其系統(tǒng)本身的局限性,大型服務(wù)器還是在UNIX下。而且正如上面所述,kqueue/epoll 與 IOCP相比,就是多了一層從內(nèi)核copy數(shù)據(jù)到應用層的阻塞,從而不能算作asynchronous I/O類。但是,這層小小的阻塞無足輕重,kqueue與epoll已經(jīng)做得很優(yōu)秀了。 提供一致的接口,IO Design Patterns 實際上,不管是哪種模型,都可以抽象一層出來,提供一致的接口,廣為人知的有ACE,Libevent這些,他們都是跨平臺的,而且他們自動選擇最優(yōu)的I/O復用機制,用戶只需調(diào)用接口即可。說到這里又得說說2個設(shè)計模式,Reactor and Proactor。有一篇經(jīng)典文章http://www./articles/io_design_patterns.html值得閱讀,Libevent是Reactor模型,ACE提供Proactor模型。實際都是對各種I/O復用機制的封裝。 Java nio包是什么I/O機制? 我曾天真的認為java nio封裝的是IOCP?!,F(xiàn)在可以確定,目前的java本質(zhì)是select()模型,可以檢查/jre/bin/nio.dll得知。至于java服務(wù)器為什么效率還不錯。。我也不得而知,可能是設(shè)計得比較好吧。。-_-。 =====================分割線================================== 總結(jié)一些重點:
|
|