圖解I/O的五種模型


 

1.1 五種I/O模型  

1)阻塞I/O

2)非阻塞I/O

3)I/O復用

4)事件(信號)驅動I/O

5)異步I/O

 

1.2 為什么要發起系統調用? 

因為進程想要獲取磁盤中的數據,而能和磁盤打交道的只能是內核, 進程通知內核,說要磁盤中的數據

此過程就是系統調用 

 

1.3 一次I/O完成的步驟

當進程發起系統調用時候,這個系統調用就進入內核模式, 然后開始I/O操作

I/O操作分為倆個步驟: 

         1) 磁盤把數據裝載進內核的內存空間

         2) 內核的內存空間的數據copy到用戶的內存空間中(此過程才是真正I/O發生的地方) 

注意: io調用大多數都是阻塞的

 過程分析

       整個過程:此進程需要對磁盤中的數據進行操作,則會向內核發起一個系統調用,然后此進程,將會被切換出去,

此進程會被掛起或者進入睡眠狀態,也叫不可中 斷的睡眠,因為數據還沒有得到,只有等到系統調用的結果完成后,

則進程會被喚醒,繼續接下來的操作,從系統調用的開始到系統調用結束經過的步驟:

①進程向內核發起一個系統調用,

②內核接收到系統調用,知道是對文件的請求,於是告訴磁盤,把文件讀取出來

③磁盤接收到來着內核的命令后,把文件載入到內核的內存空間里面

④內核的內存空間接收到數據之后,把數據copy到用戶進程的內存空間(此過程是I/O發生的地方)

⑤進程內存空間得到數據后,給內核發送通知

⑥內核把接收到的通知回復給進程,此過程為喚醒進程,然后進程得到數據,進行下一步操作

2.1 阻塞

    是指調用結果返回之前,當前線程會被掛起(線程進入睡眠狀態函數只有在得到結果之后,才會返回,才能繼續執行

阻塞I/O系統怎么通知進程? 

I/O 完成后, 系統直接通知進程, 則進程被喚醒   

第一階段是指磁盤把數據裝載到內核的內存中空間中

第二階段是指內核的內存空間的數據copy到用戶的內存空間 (這個才是真實I/O操作)

 

2.2 非阻塞

  非阻塞:進程發起I/O調用,I/O自己知道需過一段時間完成,就立即通知進程進行別的操作,則為非阻塞I/O

非阻塞I/O,系統怎么通知進程?

每隔一段時間,問內核數據是否准備完成,系統完成后,則進程獲取數據,繼續執行(過程也稱盲等待)

缺點無法處理多個I/O,比如用戶打開文件,ctrl+C想終止這個操作,是無法停掉的

 

            第一階段是指磁盤把數據裝載到內核的內存中空間中

 

 

            第二階段是指內核的內存空間的數據copy到用戶的內存空間 (這個才是真實I/O操作)

 

2.3 I/O多路復用 select

為什么要用I/O多路復用

  某個進程阻塞多個io ,一個進程即要等待從鍵盤輸入信息另一個准備從硬盤裝入信息

比如通過read這樣的命令調用了來個io操作,一個io完成了,一個io沒有完成阻塞着鍵盤io,磁盤io完成了 ,

這個進程也是不能響應因為鍵盤io還沒有完成,還在阻塞着 , 這個進程還在睡眠狀態 ,這個時候怎么辦 ?

由此需要I/O多路復用。

執行過程

       以后進程在調用io的時候不是直接調用io的功能,在系統內核中新增了一個系統調用幫助進程監控多個io,

一旦一個進程需要系統調用的時候向內核的一個特殊的系統調用,發起申請時,這個進程會被阻塞在這個復用器的調用上,

所以復用這個功能會監控這些io操作,任何一個io完成了,它都會告訴進程,其中某個io完成,如果進程依賴某個io操作,

那么這個時候,進程就可以繼續后面的操作能夠幫組進程監控這些io的工具叫做io復用器

Linux中  I/O 復用器

select: 就是一種實現,進程需要調用的時候,把請求發送給select ,可以發起多個,但是最多只能支持1024,先天性的限制  

poll: 沒有限制,但是多余1024個性能會下降

所以早期的apache 本身prefork mpm模型,主進程在接受多個用戶請求的時候,在線請求數超過1024,就不工作了.

那么io復用會比前倆種好嗎?

  本來進程和系統內核直接溝通的 ,在中間加一個i/o復用select, 如果是傳話,找人傳話,那么這個傳話最后會是什么樣的呢?

雖然解決了多個系統調用的問題,多路io復用本身的后半段依然是阻塞的,阻塞在select 而不是阻塞在系統調用上,

但是他第二段仍然是阻塞的,由於要掃描所有多個io操作多了一個處理機制,性能未必上升性能上也許不會有太大的改觀

 

         
                     一階段是指磁盤把數據裝載到內核的內存中空間中

                                        第二階段是指內核的內存空間的數據copy到用戶的內存空間 (這個才是真實I/O操作) 

2.4 事件驅動 

進程發起調用,通過回調函數內核會記住是那個進程申請的,一旦第一段完成了,就可以向這個進程發起通知,

這樣第一段就是非阻塞的,進程不需要盲等了但是第二段依然是阻塞的

 

事件驅動機制(event-driven)

正是由於事件驅動機制 ,才能同時相應多個請求的

比如一個web服務器一個進程響應多個用戶請求

缺陷第二段仍然是阻塞的

倆種機制

如果一個事件通知一個進程,進程正在忙進程沒有聽見這個怎么辦?

水平觸發機制: 內核通知進程來讀取數據,進程沒來讀取數據,內核需要一次一次的通知進程

邊緣觸發機制: 內核只通知一次讓進程來取數據,進程在超時時間內,隨時可以來取數據, 把這個事件信息狀態發給進程,好比發個短息給進程,

nginx

     nginx默認采用了邊緣觸發驅動機制 

 

    

 

第一階段是指磁盤把數據裝載到內核的內存中空間中

第二階段是指內核的內存空間的數據copy到用戶的內存空間 (這個才是真實I/O操作)

 

 

2.5 異步AIO

無論第一第二段不再向系統調用提出任何反饋只有數據完全復制到服務進程內存中后才向服務進程返回ok的信息,其它時間,

進程可以隨意做自己的事情,直到內核通知ok信息

注意: 只在文件中可以實現AIO, 網絡異步IO 不可能實現

nginx:
nginxfile IO 文件異步請求的
一個進程響應N個請求
靜態文件界別支持sendfile   
避免浪費復制時間:  mmap 支持內存映射,內核內存復制到進程內存這個過程不需要復制了直接映射到進程內存中
支持邊緣觸發
支持異步io
解決了c10k的問題
c10k : 有一萬個同時的並發連接
c100k: 你懂得

 

 

第一階段是指磁盤把數據裝載到內核的內存中空間中

第二階段是指內核的內存空間的數據copy到用戶的內存空間 (這個才是真實I/O操作)

 

前四種I/O模型屬於同步操作,最后一個AIO則屬於異步操作 

2.6 五種模型比較

 

同步阻塞

倆段都是阻塞的,所有數據准備完成后,才響應

同步非阻塞

磁盤從磁盤復制到內核內存中的時候不停詢問內核數據是否准備完成盲等

性能有可能更差 ,看上去他可以做別的事情了但是其實他在不停的循環

但還是有一定的靈活性的

缺點無法處理多個I/O,比如用戶打開文件,ctrl+C想終止這個操作,是無法停掉的

同步IO

如果第二段是阻塞的 ,代表是同步的

第一種,第二種,io復用,事件驅動,都是同步的.  

異步IO

內核后台自己處理 ,把大量時間拿來處理用戶請求

 

 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM