I/O Models

概念

Input/Output

  • 在硬件層面,I/O是字節在硬盤、網卡、鍵盤等設備到內存之間流動的過程。
  • 在應用軟件的角度上,Input是應用軟件經過直接或間接地調用操做系統(kernel)提供的IO接口訪問應用進程外部數據的過程。這個過程一般包括兩個階段:第一階段是在向內核提交需求(調用kernel接口);第二階段是內核將這部分數據從內核緩衝區複製到應用緩衝區域即成功得到數據(完成任務)。Output是應用調用內核IO接口嚮應用進程外輸出數據的過程。一樣地一般涉及兩個階段:第一階段是直接或間接調用內核IO接口請求輸出數據;第二階段內核將數據從應用緩衝區複製到目的地。從第一階段進入第二階段須要知足必定條件。對於Input,條件一般包括應用須要的數據在內核緩衝區準備好並能夠複製到應用緩衝區中。對於Output,條件包括目標文件有足夠空間存放數據。
  • 對於應用程序來講,向網絡(Network)輸出輸入數據與讀寫文件本質上都是I/O:前者是將數據寫到網卡,最終發到目的主機,然後者是將數據寫到硬盤。在Linux操做系統中,全部外設都被映射成文件,即對外設的操做都被映射成對文件的操做。TCP協議中,通訊連接的兩端是Socket(套接字,由IP地址和端口組成)。服務端應用進程與客戶端進程的通訊就是經過讀寫Socket文件:服務端進程想要接收客戶端發送的數據,就要從本機上與該客戶端對應的Socket文件輸入流中讀取數據,若是想發送數據,就要向該Socket文件輸出流寫入數據。因此應用程序間的網絡通訊本質上只是I/O的一種。

中斷

中斷包括程序中斷、時間中斷、I/O中斷和硬件失效中斷。當程序向內核發出I/O請求,內核執行I/O程序,I/O設備經過中斷的方式通知內核:」已發現須要的數據「,內核執行中斷程序迴應硬件設備:」已獲悉「。網絡

中斷機制在每一個OS中均可能有不同的實現,下面簡述Linux系統中的通常中斷機制,具體實現仍取決於開發者。異步

上半部分:內核經過中斷處理程序及時迴應發出中斷請求的硬件(儘快返回被中斷的工做中)。當I/O事件完成,I/O設備發送中斷信號到中斷控制器芯片,若是此時處理器容許中斷,中斷控制器向處理器發送一箇中斷請求的電信號,處理器在指令週期中的檢測中斷階段檢測到I/O中斷請求,馬上中止當前處理的程序並屏蔽中斷,跳到預先由內核設置好的內存地址讀取指令並執行,這個地址就是中斷處理函數的入口,內核在這個函數內計算出中斷號,根據中斷號運行對應的處理程序(該中斷處理程序來自於外部設備的驅動),完成中斷處理程序後即對硬件的中斷請求做出了迴應。在這個階段有時還會作另一些一樣對時間很敏感的工做,例如從硬件拷貝數據到系統內存緩衝區,如當網卡接收到的數據,以後能夠返回到被中斷的程序中繼續執行指令。函數

下半部分:完成對時間不是很是敏感的工做,這部分工做能夠日後推遲。例如處理系統內存中從硬件接收到的數據,若是此時完成了一個I/O請求的條件,能夠將阻塞在此I/O請求上的進程設置爲就緒態。‘spa

系統調用處理程序

用戶空間的程序沒法直接執行內核代碼,由於內核的函數存放在受保護的系統空間內。應用程序經過軟中斷的方式,通知系統本身須要執行一個系統調用:經過引起一個異常促使系統從用戶態切換到系統態,執行一個異常處理函數,這個函數就是系統調用處理程序。操作系統

阻塞(Blocking)與  非阻塞(Non-Blocking)

阻塞態是進程的一種執行態,此時進程不能被內核調度繼續執行。阻塞的緣由有不少種,能夠概括爲等待的事件仍未發生。在這裏咱們討論的阻塞非阻塞就是進程在執行I/O調用以後的狀態。線程

當進程執行一個系統調用以請求I/O資源,但內核檢測到I/O資源被佔用或者數據未準備好,因此不能馬上響應線程爲其服務,進程的狀態被內核調整爲阻塞態,直到該I/O資源準備好並返回系統調用的結果,內核將進程執行態設置爲就緒態。相反,若是進程執行一個系統調用,該系統調用不管I/O資源準備好與否都當即返回某個結果,進程就不須要進入阻塞態且能夠繼續執行後續指令。兩種系統調用的區別在於:當操做系統沒有準備好程序申請的I/O資源時,進程是否會被內核設置爲阻塞態。設計

同步(synchronous )與  異步(Asynchronous)

同步與異步是對請求方與被請求方之間的通訊方式。對象

同步(synchronous ):當請求方發送請求後,只能作獲取被請求方的響應的事情,能夠是什麼都不作,等待被請求方迴應結果(阻塞),也能夠是不斷地詢問被請求方是否有結果(非阻塞、輪詢-polling),但就是不會作與此次請求無關的其餘任務。當進程執行I/O請求後,被阻塞等待內核通知I/O事件完成,或者非阻塞地經過輪詢的方式詢問內核I/O事件是否完成,而不會去執行其餘不相干的代碼。blog

異步(Asynchronous):當請求方發送請求後,不關心結果,直接執行其餘任務的操做(非阻塞),等到被請求方處理完請求後再通知請求方,請求方在合適的時候再處理這個結果,或者在請求的時候就告訴被請求方當處理完請求後幫其乾點什麼。當程序執行I/O系統調用,該系統調用是非阻塞的,即會當即返回一個結果,程序能夠繼續執行後面的指令,這些指令不會涉及到這個結果,當內核通知其I/O事件完成後纔會考慮處理結果。或者設置回調函數,當I/O事件完成時執行回調函數。接口

I/O Models

阻塞I/O(Blocking I/O:BIO)Model

BIO模型是同步阻塞的。

阻塞:進程執行系統調用請求獲取數據,被阻塞直到數據複製到系統緩衝區,並從系統緩衝區複製到應用緩衝區。

同步:因爲在內核準備數據這段時間,程序沒有作其餘工做,直到獲取到內核的結果。

graphics/06fig01.gif

非阻塞I/O(Non-Blocking I/O:NIO)Model

NIO模型是同步非阻塞的。

非阻塞於:進程執行系統調用請求數據,當系統調用檢測系統緩衝區沒有準備好數據時,並無讓程序等待直到數據準備好,而是直接返回一個負數表明數據沒有準備好,程序能夠繼續執行後面的指令。

同步於:雖然程序能夠繼續執行後面的指令,可是想先收到數據再作其餘工做,經過輪詢的方式不斷詢問內核數據是否準備好。

graphics/06fig02.gif

I/O 多路複用(I/O Multiplexing)Model

在多路複用模型中,複用的是線程,即用一個線程監聽多個I/O流上可讀可寫的事件。

在以前的BIO模型與NIO模型中,服務端在一個線程裏只等待一個客戶端Socket文件I/O流上可讀或可寫的事件發生,這意味着一個線程只服務一個客戶端,當客戶端Socket文件的輸入流不可讀,線程同步地等待直到該輸入流可讀,而後讀取數據並處理。若是服務端進程要同時處理多個客戶端即監聽多個Socket文件上的I/O流可讀寫事件,須要增長線程數目。值得注意的是,除了根據客戶端數目1:1地增長線程數目來服務多個客戶端,也能夠經過設置線程池的方式,用若干個線程服務多個客戶端。但本質上,這兩種I/O模型中每一個線程都只能同時監聽一個Socket文件上的I/O流事件。

在I/O多路複用模型中,服務端在一個線程裏能夠同時監聽多個客戶端Socket文件上的I/O流。線程等待多個I/O流上的可讀可寫事件,當一個或以上的I/O流可讀/可寫事件發生,內核返回被包裝好的I/O流對象,線程串行地根據事件的類型對這些I/O流進行讀或者寫。

I/O多路複用是同步阻塞的。

阻塞於:當沒有一個I/O上有可讀或可寫事件發生,線程是被阻塞的,select()函數不能立刻返回(select函數選擇一個或以上的可讀寫I/O流)。值得注意的是,有的文章會根據:即便有部分I/O流不知足讀/寫條件也不會阻塞整個線程妨礙其餘I/O流讀寫這一觀點,認爲I/O複用是非阻塞的,這是對的,只是你們角度不一樣。

同步於:由於在發送I/O請求(select函數)後若是沒有可讀或可寫事件發生,線程是阻塞的,線程沒辦法執行其餘工做,因此是同步的。

graphics/06fig03.gif

異步I/O模型(Asynchronous I/O Model)

異步I/O模型是異步非阻塞的。在該模型中,線程爲I/O請求執行的系統調用不會阻塞線程而是立刻返回,這次請求僅僅是通知內核將需求數據複製到應用緩衝區,以後線程能夠執行後面的指令,與NIO不一樣的是,AIO不會以輪詢地方式等待I/O操做完成,而是去執行其餘工做,直到內核將數據複製到應用緩衝區再通知線程,所以AIO是非阻塞的,異步的。

 graphics/06fig05.gif

參考

  • 《操做系統——精髓與設計原理》
  • 《 UNIX Network Programming, Volume 1 》 
  • 《Linux內核設計與實現》
  • 《Computer Systems - A Programmer's Perspective》
相關文章
相關標籤/搜索