1. 程式人生 > >五種程式設計模型(IO模型)

五種程式設計模型(IO模型)

 

1、同步非同步,阻塞非阻塞區別聯絡
    實際上同步與非同步是針對應用程式與核心的互動而言的。同步過程中程序觸發IO操作並等待(也就是我們說的阻塞)或者輪詢的去檢視IO操作(也就是我們說的非阻塞)是否完成。 非同步過程中程序觸發IO操作以後,直接返回,做自己的事情,IO交給核心來處理,完成後核心通知程序IO完成。
同步和非同步針對應用程式來,關注的是程式中間的協作關係;阻塞與非阻塞更關注的是單個程序的執行狀態。
同步有阻塞和非阻塞之分,非同步沒有,它一定是非阻塞的。
阻塞、非阻塞、多路IO複用,都是同步IO,非同步必定是非阻塞的,所以不存在非同步阻塞和非同步非阻塞的說法。真正的非同步IO需要CPU的深度參與。換句話說,只有使用者執行緒在操作IO的時候根本不去考慮IO的執行全部都交給CPU去完成,而自己只等待一個完成訊號的時候,才是真正的非同步IO。所以,拉一個子執行緒去輪詢、去死迴圈,或者使用select、poll、epool,都不是非同步。
同步

:執行一個操作之後,程序觸發IO操作並等待(也就是我們說的阻塞)或者輪詢的去檢視IO操作(也就是我們說的非阻塞)是否完成,等待結果,然後才繼續執行後續的操作。
非同步:執行一個操作後,可以去執行其他的操作,然後等待通知再回來執行剛才沒執行完的操作。
阻塞:程序給CPU傳達一個任務之後,一直等待CPU處理完成,然後才執行後面的操作。
非阻塞:程序給CPU傳達任我後,繼續處理後續的操作,隔斷時間再來詢問之前的操作是否完成。這樣的過程其實也叫輪詢。
2、IO模型(五種程式設計模型)
這裡統一使用Linux下的系統呼叫recv作為例子,它用於從套接字上接收一個訊息,因為是一個系統呼叫,所以呼叫時會從使用者程序空間切換到核心空間執行一段時間再切換回來
。預設情況下recv會等到網路資料到達並且複製到使用者程序空間或者發生錯誤時返回,而第4個引數flags可以讓它馬上返回。

阻塞IO模型
使用recv的預設引數一直等資料直到拷貝到使用者空間,這段時間內程序始終阻塞。A同學用杯子裝水,開啟水龍頭裝滿水然後離開。這一過程就可以看成是使用了阻塞IO模型,因為如果水龍頭沒有水,他也要等到有水並裝滿杯子才能離開去做別的事情。很顯然,這種IO模型是同步的。

 

非阻塞IO模型
改變flags,讓recv不管有沒有獲取到資料都返回,如果沒有資料那麼一段時間後再呼叫recv看看,如此迴圈。B同學也用杯子裝水,開啟水龍頭後發現沒有水,它離開了,過一會他又拿著杯子來看看……在中間離開的這些時間裡,B同學離開了裝水現場(回到使用者程序空間),可以做他自己的事情。這就是非阻塞IO模型。但是它只有是檢查無資料的時候是非阻塞的,在資料到達的時候依然要等待複製資料到使用者空間(等著水將水杯裝滿),因此它還是同步IO。

 

IO複用模型
這裡在呼叫recv前先呼叫select或者poll,這2個系統呼叫都可以在核心準備好資料(網路資料到達核心)時告知使用者程序,這個時候再呼叫recv一定是有資料的。因此這一過程中它是阻塞於select或poll,而沒有阻塞於recv,有人將非阻塞IO定義成在讀寫操作時沒有阻塞於系統呼叫的IO操作(不包括資料從核心複製到使用者空間時的阻塞,因為這相對於網路IO來說確實很短暫),如果按這樣理解,這種IO模型也能稱之為非阻塞IO模型,但是按POSIX來看,它也是同步IO,那麼也和樓上一樣稱之為同步非阻塞IO吧。
這種IO模型比較特別,分個段。因為它能同時監聽多個檔案描述符(fd)。這個時候C同學來裝水,發現有一排水龍頭,舍管阿姨告訴他這些水龍頭都還沒有水,等有水了告訴他。於是等啊等(select呼叫中),過了一會阿姨告訴他有水了,但不知道是哪個水龍頭有水,自己看吧。於是C同學一個個開啟,往杯子裡裝水(recv)。這裡再順便說說鼎鼎大名的epoll(高效能的代名詞啊),epoll也屬於IO複用模型,主要區別在於舍管阿姨會告訴C同學哪幾個水龍頭有水了,不需要一個個開啟看(當然還有其它區別)。

 

訊號驅動IO模型
通過呼叫sigaction註冊訊號函式,等核心資料準備好的時候系統中斷當前程式,執行訊號函式(在這裡面呼叫recv)。D同學讓舍管阿姨等有水的時候通知他(註冊訊號函式),沒多久D同學得知有水了,跑去裝水。是不是很像非同步IO?很遺憾,它還是同步IO(省不了裝水的時間啊)。

 

非同步IO模型
呼叫aio_read,讓核心等資料準備好,並且複製到使用者程序空間後執行事先指定好的函式。E同學讓舍管阿姨將杯子裝滿水後通知他。整個過程E同學都可以做別的事情(沒有recv),這才是真正的非同步IO。

 

總結
IO分兩階段:
  1.資料準備階段
  2.核心空間複製回用戶程序緩衝區階段
一般來講:阻塞IO模型、非阻塞IO模型、IO複用模型(select/poll/epoll)、訊號驅動IO模型都屬於同步IO,因為階段2是阻塞的(儘管時間很短)。只有非同步IO模型是符合POSIX非同步IO操作含義的,不管在階段1還是階段2都可以幹別的事。
linux的五種IO模式/非同步模式:
  同步阻塞I/O 
  同步非阻塞I/O
  同步I/O複用模型 
  同步訊號驅動I/O 
  非同步I/O模型