1,IO模型分類如下:
-
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
當用戶進程調用了recvfrom這個(system call)系統調用,kernel就開始了IO的第一個階段:(wait for data)準備數據,在這時kernel要等待足夠的數據到來(如對於network io來說,很多時候數據在一開始還沒有到達,還沒收到完整的UDP包),而在這過程對於用戶進程是(blocking )阻塞的;當kernel一直等到數據準備好了,它就會將數據從kernel中拷貝到用戶內存,然後kernel返回結果,用戶進程才解除block的狀態,重新運行起來。
所以,blocking IO的特點就是在IO執行的兩個階段都被block了
nonblocking I/O
可以看出,用戶進程不斷(polling)輪詢 發出recvfrom,而如果kernel中的數據還沒有準備好,那麼它並不會block用戶進程,而是立刻返回一個error。用戶根據這error標識知道kernel中的數據還沒有準備好,再次發出recvfrom 一旦kernel中的數據準備好了,並且又再次收到了用戶進程的system call,那麼它馬上就將數據拷貝到了用戶內存,然後返回。
I/O multiplexing (select and poll )
signal driven I/O (SIGIO)
asynchronous I/O (the POSIX aio_functions)
2.各個IO Model的比較如圖所示:
select, epoll,kqueue ,iocp 對應的模型如下 :
select -> I/O multiplexing (select and poll )
epoll -> epoll
is a scalable I/O event notification mechanism
for Linux ,
kqueue -> Kqueue is a scalable event notification interface introduced in FreeBSD 4.1
iocp -> asynchronous I/O (the POSIX aio_ functions) windows(採用)
select, epoll,kqueue 都是屬於同一模型,只不過是 epoll,kqueue解決了select的一些侷限性,更加高級點
可以看作有了第4種模型的某些特性,如callback機制等
他們無輪詢 。因爲他們用callback取代了。想想 看,當套接字比較多的時候,每次select()都要通過遍歷FD_SETSIZE個Socket來完成調度,不管哪個Socket是活躍的,都遍歷一 遍。這會浪費很多CPU時間。如果能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操作,那就避免了輪詢,這正是epoll與kqueue做的。
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。 有一篇經典文章http://www.artima.com/articles/io_design_patterns.html 值得閱讀,Libevent是Reactor 模型,ACE提供Proactor 模型。實際都是對各種I/O複用機制的封裝。
Java nio包是什麼I/O機制?
我曾天真的認爲java nio封裝的是IOCP。。現在可以確定,目前的java本質是select()模型,可以檢查/jre/bin/nio.dll得知。至於java服務器爲什麼效率還不錯。。我也不得而知,可能是設計得比較好吧。。-_-。
3.總結一些重點:
- 只有IOCP是asynchronous I/O,其他機制或多或少都會有一點阻塞。
- select低效是因爲每次它都需要輪詢。但低效也是相對的,視情況而定,也可通過良好的設計改善
- epoll, kqueue是Reacor模式,IOCP是Proactor模式。
- java nio包是select模型。。