高性能服務器框架--I/O模型

        轉載地址:http://www.linuxidc.com/Linux/2014-10/108476.htm

         socket在創建的時候默認是阻塞的。我們可以通過socket系統調用的第二個參數傳遞SOCK_NONBLOCK標誌,或者通過 fcntl 系統調用的F_SETFL命令,將其設置爲非阻塞的。阻塞和非阻塞的概念能應用與所有文件描述符,不僅僅是socket,我們稱阻塞的文件描述符爲阻塞I/O,非阻塞的文件描述符爲非阻塞I/O.

        針對阻塞I/O執行的系統調用可能因爲無法立即完成而被操作系統掛起,直到等待的事件發生爲止。比如,客戶端通過connect向服務器發起連接時,connect將首先發送同步報文段給服務器,然後等待服務器返回確認報文段,如果服務器的確認報文段沒有立即到達客戶端,則connect調用將被掛起,直到客戶端收到確認報文段並喚醒connect調用,socket的基礎API中,可能被阻塞的系統調用包括acept send rev connect.

        針對非阻塞I/O執行的系統調用則總是立即返回,而不管事件是否已經發生,如果事件沒有立即發生,這些系統調用就返回-1,和出錯的情況一樣,此時我們必須根據errno來分情況,對accept send recv而言,事件未發生時errno通常被設置成EAGAIN或者EWOULDBLOCK(意思爲期望阻塞),對於connect,errno則被設置爲EINPROGRESS(意思爲正在處理中)。

        很顯然,我們只有在事件已經發生的情況下操作非阻塞i/o(讀寫等),才能提高程序的效率,因此,非阻塞I/O通常要和其他I/O通知機制一起使用,比如I/O複用和SIGIO信號。

        I/O複用是最常用兩個的I/O通知機制,他指的是,應用程序通過I/O複用函數向內核註冊一組事件,內核通過I/O複用函數把其中就緒的事件通知給應用程序,Linux上常用的I/O複用函數是select、poll epoll_wait。需要明白的是,I/O複函數本身是阻塞的,他們能提高程序效率的原因在於他們具有同時監聽多個I/O事件的能力。

        SIGIO信號也可以用來報告I/O事件。當目標文件 描述符上有事件發生時,SIGIO信號的信號處理函數將被觸發,我們也就可以在該信號處理函數中對目標文件描述II符執行非阻塞I/O操作了。

         從理論上說,阻塞I/O,I/O複用和信號驅動I/O都是同步I/O模型,因爲在這三種I/O模型中,I/O讀寫操作,都是在I/O事件發生之後,由應用程序完成的,在POSIX規範所定義的異步I/O模型則不同。對於異步I/O而言,用戶可以直接對I/O執行讀寫操作,這些操作告訴內核用戶讀寫緩衝區的位置,以及I./O操作完成之 後內核通知應用程序的方式。異步I/O的讀寫總是立即返回,而不論I/O是否阻塞,因爲真正的讀寫操作已經由內核接管,也就是說,同步I/O模型要求用戶代碼自行執行I/O操作(將數據從內核緩衝區讀入用戶緩衝區,或將數據從用戶緩衝區寫入內核緩衝區),而異步I/O機制則由內核來執行I/O操作(數據在內核緩衝區和用戶緩衝區之間的移動是由內核在“後臺”完成的)。你可以這麼認爲,同步I/O嚮應用程序通知的是I/O就緒事件,異步I/O想應用程序通知的是I/O完成事件。linux環境下,aio.h頭文件中定義了函數提供了異步I/O支持。

總結

        I/O模型 讀寫操作和阻塞階段

        阻塞I/O 程序阻塞與讀寫操作

        I/O複用 程序阻塞於I/O複用系統調用,但可同時監聽多個I/O事件,對I/O本身讀寫操作是非阻塞的

        SIGIO信號 信號觸發讀寫就緒事件,用戶程序執行讀寫操作,程序沒有阻塞階段

        異步I/O 內核執行讀寫並觸發讀寫完成事件,程序沒有阻塞階段

        同時,在併發模型中也有同步/異步的方式,但是和這裏的概念不同。

        在I/O模型中,同步和異步區分的是內核嚮應用程序通知的是何種I/O事件(是就緒事件還是完成事件),以及該由誰來完成I/O讀寫(是應用程序還是內核),在併發模型中,同步指的是程序完全按照代碼序列的順序執行,異步值得是程序執行需要由系統事件來驅動,常見的系統事件包括中斷,信號等

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章