對于一次IO訪問,以read為例,數(shù)據(jù)會先被拷貝到操作系統(tǒng)的緩沖區(qū),然后從操作系統(tǒng)的緩沖區(qū)拷貝到用戶的地址空間。read操作會經(jīng)歷下面兩個階段:
第一階段:等待數(shù)據(jù)準備就緒
第二階段:將數(shù)據(jù)從內(nèi)核拷貝到進程中(內(nèi)核態(tài)到用戶態(tài))
阻塞I/O模型
所有操作是阻塞的,直到數(shù)據(jù)包到達且被復制到應用進程的緩沖區(qū)中或者發(fā)生錯誤返回。以recvfrom(經(jīng)過socket接收數(shù)據(jù))調(diào)用舉例。

非阻塞I/O模型
recvfrom調(diào)用如果緩沖區(qū)沒有數(shù)據(jù)的話直接返回EWOULDBLOCK錯誤,一般對非阻塞I/O模型進行輪訓檢查這個狀態(tài)看內(nèi)核是否有數(shù)據(jù)到來。

I/O復用模型
Linux提供select/poll,進程可以將一個或多個fd(文件描述符)傳遞給select或poll調(diào)用,阻塞在select上,select負責偵測fd是否處于就緒狀態(tài)。

多路復用技術(shù)通過把多個I/O的阻塞復用到一個select的阻塞上,從而使系統(tǒng)在單線程的情況下處理多客戶端請求,最大的優(yōu)勢是系統(tǒng)開銷小。
Linux的多路復用系統(tǒng)調(diào)用有:select、pselect、poll、epoll。
select固有的缺陷:
* 打開的fd數(shù)量受限(受限于FD_SIZE,修改需要重新編譯內(nèi)核,會導致性能下降)
* 采用輪訓的方式,隨著fd的增加性能線性下降
epoll的優(yōu)化:
* 打開fd僅受限于操作系統(tǒng)的最大文件句柄數(shù)
* 由每個fd上的callback來實現(xiàn)對活躍的socket進行操作,避免了輪訓的問題
* 采用mmap加速內(nèi)核與用戶控件的數(shù)據(jù)傳遞(共享內(nèi)存)
* API更加簡單
信號驅(qū)動I/O模型
開啟套接口信號驅(qū)動I/O功能,并通過系統(tǒng)調(diào)用sigaction執(zhí)行信號處理(非阻塞)。當數(shù)據(jù)準備就緒是,就會該進程生成一個SIGIO信號,通過信號回調(diào)通知應用程序調(diào)用recvfrom來讀取數(shù)據(jù)。

異步I/O
告知內(nèi)核啟動某個操作,并讓內(nèi)核在整個操作完成之后(包括數(shù)據(jù)從內(nèi)核到用戶空間的復制)通知應用程序。
和信號驅(qū)動模型的區(qū)別是:信號驅(qū)動提供信號通知應用程序何時可以開始IO操作;異步IO由直接通知何時完成了IO操作。

五種IO模型的對比
