I/O模型 與 select, iocp, epoll,kqueue

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.總結一些重點:

  1. 只有IOCP是asynchronous I/O,其他機制或多或少都會有一點阻塞。
  2. select低效是因爲每次它都需要輪詢。但低效也是相對的,視情況而定,也可通過良好的設計改善
  3. epoll, kqueue是Reacor模式,IOCP是Proactor模式。
  4. java nio包是select模型。。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章