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