关于Blocking IO, Non-Blocking IO 和 Asynchronous I/O的理解
文章寫得很詳細很清楚了,對我的理解幫助很大。
轉載自:http://www.cnblogs.com/whyandinside/archive/2012/03/04/2379234.html。
概括來說,一個IO操作可以分為兩個部分:發出請求、結果完成。如果從發出請求到結果返回,一直Block,那就是Blocking IO;如果發出請求就可以返回(結果完成不考慮),就是non-blocking IO;如果發出請求就返回,結果返回是Block在select或者poll上的,則其只能稱為IO multiplexing;如果發出請求就返回,結果返回通過Call Back的方式被處理,就是AIO。
文[2]中圖畫的不錯,說的也比較清楚借來用一下。
Blocking IO
這個最好理解了,在Blocking IO模式下,函數調用只有在操作完成后才會返回。下圖是它調用過程的圖示:
重點解釋下上圖,下面例子都會講到。首先application調用 recvfrom()轉入kernel,注意kernel有2個過程,wait for data和copy data from kernel to user。直到最后copy complete后,recvfrom()才返回。此過程一直是阻塞的。
Non-Blocking IO
Non-Blocking 是Blocking的反,也就是說,即使操作沒有完成,函數也可以返回。調用過程如下:
可以看見,如果直接操作它,那就是個輪詢。。直到內核緩沖區有數據
AIO也是這樣啊?對!這是Non-Blocking IO 和AIO的共同點。其實從概念層面來說Non-Blocking IO 就是AIO,他們沒有什么區別。但是Non-Blocking IO是對文件描述符(*nix)或者Handle(Windows)的設置,在執行操作時不需要特殊的數據結構。Non-Blocking IO提交請求后只能通過提交的操作函數來查詢操作是否完成,這是一個很大的限制。而AIO往往會提供多種通知或者查詢機制,也就是說用Non-Blocking IO時只能輪詢,而AIO有更多選擇。所以是否支持輪詢外的其他機制是AIO和Non-Blocking IO的區別。
Non-Blocking IO和Blocking IO的區別僅僅在操作是否能夠立刻完成,如果能夠立刻完成,IO函數的行為是一樣的;如果不能立刻完成,Non-Blocking IO會返回EAGAIN或者EWOULDBLOCK,而Blocking IO會一直阻塞。
I/O multiplexing (select and poll)
最常見的I/O復用模型,select。
select先阻塞,有活動套接字才返回。與blocking I/O相比,select會有兩次系統調用,但是select能處理多個套接字。
signal driven I/O (SIGIO)
只有UNIX系統支持,感興趣的課查閱相關資料
與I/O multiplexing (select and poll)相比,它的優勢是,免去了select的阻塞與輪詢,當有活躍套接字時,由注冊的handler處理。
Asynchronous I/O (the POSIX aio_functions)
很少有*nix系統支持,windows的IOCP則是此模型。
The POSIX asynchronous I/O (AIO) interface allows applications to initiate one or more I/O operations that are performed asynchronously (i.e., in the background). The application can elect to be notified of completion of the I/O operation in a variety of ways: by delivery of a signal, by instantiation of a thread, or no notification at all.
AIO讓應用發起一個操作請求,讓這個請求被異步地執行。應用可以選擇在操作完成時被通知到或者不被通知。所以通知機制并不是AIO的核心,但是需要提供幾種選擇。在Windows上,Overlapped IO是AIO的實現,IOCP在Overlapped IO的基礎上提供了高效的通知機制。
完全異步的I/O復用機制,因為縱觀上面其它四種模型,至少都會在由kernel copy data to application時阻塞。而該模型是當copy完成后才通知application,可見是純異步的。好像只有windows的完成端口是這個模型,效率也很出色。
下面是以上五種模型的比較
可以看出,越往后,阻塞越少,理論上效率也是最優。
下面可以把select,epoll,iocp,kqueue按號入座。
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服務器為什么效率還不錯。。我也不得而知,可能是設計得比較好吧。。-_-。
=====================分割線==================================
總結一些重點:
只有IOCP是asynchronous I/O,其他機制或多或少都會有一點阻塞。 select低效是因為每次它都需要輪詢。但低效也是相對的,視情況而定,也可通過良好的設計改善 epoll, kqueue是Reacor模式,IOCP是Proactor模式。 java nio包是select模型。。
Reference:
http://www.artima.com/articles/io_design_patterns.html
http://hi.baidu.com/ailuoli/blog/item/f9fe370f0dee7bf1ab6457e7.html
總結
以上是生活随笔為你收集整理的关于Blocking IO, Non-Blocking IO 和 Asynchronous I/O的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 64位win7安装vs2010出现“组件
- 下一篇: 计算程序运行时间(time_t, clo