Linux下5種IO模型的小結
接觸網路程式設計,我們時常會與各種與IO相關的概念打交道:同步(Synchronous)、非同步(ASynchronous)、阻塞(blocking)和非阻塞(non-blocking)。關於概念的區別在知乎上看到一位朋友(連結)打了一個比較形象的比喻:
你打電話問書店老闆有沒有《分散式系統》這本書,如果是同步通訊機制,書店老闆會說,你稍等,”我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。
而非同步通訊機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,然後直接掛電話了(不返回結果)。然後查好了,他會主動打電話給你。在這裡老闆通過“回電”這種方式來回調。你打電話問書店老闆有沒有《分散式系統》這本書,你如果是阻塞式呼叫,你會一直把自己“掛起”,直到得到這本書有沒有的結果。如果是非阻塞式呼叫,你不管老闆有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鐘check一下老闆有沒有返回結果。
在這裡阻塞與非阻塞與是否同步非同步無關。跟老闆通過什麼方式回答你結果無關。
同步與非同步的主要區別就在於:會不會導致請求程序(或執行緒)阻塞。同步會使請求程序(或執行緒)阻塞而非同步不會。
linux下有五種常見的IO模型,其中只有一種非同步模型,其餘皆為同步模型。如圖:
阻塞IO模型是最常見的IO模型了,對於所有的“慢速裝置”(socket、pipe、fifo、terminal)的IO預設的方式都是阻塞的方式。阻塞就是程序放棄cpu,讓給其他程序使用cpu。程序阻塞最顯著的表現就是“程序睡眠了”。阻塞的時間通常取決於“資料”是否到來。
非阻塞IO模型
非阻塞IO就是設定IO相關的系統呼叫為non-blocaking,隨後進行的IO操作無論有沒有可用資料都會立即返回,並設定errno為EWOULDBLOCK或者EAGAIN。我們可以通過主動check的方式(polling,輪詢)確保IO有效時,隨之進行相關的IO操作。當然這種方式看起來就似乎不太靠譜,浪費了太多的CPU時間,用寶貴的CPU時間做輪詢太不靠譜兒了。圖示:
多路複用IO模型
多路複用是讓阻塞發生在我們的多路複用IO操作的系統呼叫上面,而不是我們真正去執行IO的系統呼叫。使用這個方式的好處就是可以同時監控多個用於IO的檔案描述符。詳細的使用方式之前寫了一篇部落格有提到:http://www.cnblogs.com/ittinybird/p/4574397.html
訊號驅動IO模型
所謂訊號驅動,就是利用訊號機制,安裝訊號SIGIO的處理函式(進行IO相關操作),通過監控檔案描述符,當其就緒時,通知目標程序進行IO操作(signal handler)。具體使用方法之前部落格也有說明:http://www.cnblogs.com/ittinybird/p/4574397.html
非同步IO模型
Linux上非同步IO有一組POSIX規定的介面,已aio開頭的幾個SYSCALL。如下:
int aio_read(struct aiocb *aiocbp); int aio_write(struct aiocb *aiocbp);
ssize_t aio_return(struct aiocb *aiocbp);
使用時記得 Link with -lrt.
引數看起來給人一種很簡潔的假象。其實相較於其他模型的引數一個也沒有少,只是放到了結構體裡邊了。先看一下struct aiocb這個結構的原型吧,標頭檔案是”aio.h“。
struct aiocb { int aio_fildes; /* File desriptor. */ int aio_lio_opcode; /* Operation to be performed. */ int aio_reqprio; /* Request priority offset. */ volatile void *aio_buf; /* Location of buffer. */ size_t aio_nbytes; /* Length of transfer. */ struct sigevent aio_sigevent; /* Signal number and value. */ /* Internal members. */ struct aiocb *__next_prio; int __abs_prio; int __policy; int __error_code; __ssize_t __return_value; #ifndef __USE_FILE_OFFSET64 __off_t aio_offset; /* File offset. */ char __pad[sizeof (__off64_t) - sizeof (__off_t)]; #else __off64_t aio_offset; /* File offset. */ #endif char __unused[32]; };
下圖是關於非同步IO模型的圖示:
參考aio(7) - Linux manual page http://man7.org/linux/man-pages/man7/aio.7.html
sigevent(7) - Linux manual page http://man7.org/linux/man-pages/man7/sigevent.7.html
5張模型圖片出處 《UNIX網路程式設計卷1》 史蒂文斯