1. 程式人生 > >Linux下5種IO模型的小結

Linux下5種IO模型的小結

概述

    接觸網路程式設計,我們時常會與各種與IO相關的概念打交道:同步(Synchronous)、非同步(ASynchronous)、阻塞(blocking)和非阻塞(non-blocking)。關於概念的區別在知乎上看到一位朋友(連結)打了一個比較形象的比喻:

你打電話問書店老闆有沒有《分散式系統》這本書,如果是同步通訊機制,書店老闆會說,你稍等,”我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。
而非同步通訊機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,然後直接掛電話了(不返回結果)。然後查好了,他會主動打電話給你。在這裡老闆通過“回電”這種方式來回調。

你打電話問書店老闆有沒有《分散式系統》這本書,你如果是阻塞式呼叫,你會一直把自己“掛起”,直到得到這本書有沒有的結果。如果是非阻塞式呼叫,你不管老闆有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鐘check一下老闆有沒有返回結果。

在這裡阻塞與非阻塞與是否同步非同步無關。跟老闆通過什麼方式回答你結果無關。

    同步與非同步的主要區別就在於:會不會導致請求程序(或執行緒)阻塞。同步會使請求程序(或執行緒)阻塞而非同步不會。

    linux下有五種常見的IO模型,其中只有一種非同步模型,其餘皆為同步模型。如圖:

阻塞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》 史蒂文斯