`阻塞/非阻塞` 和 `同步/非同步` 不是乙個概念。舉幾個簡單的例子。
當程序呼叫乙個進行io操作的api時(比如read函式),在資料沒有到達前,read 會掛起,程序會卡住。在資料讀取完畢返回給程序時,
read 返回(返回值為讀取到的位元組數,資料從核心拷貝到使用者空間),然後程序繼續執行。那麼這次 read 呼叫,是阻塞的。
非阻塞就是 read 在資料沒有讀取完畢前,就返回了(返回值為-1,errno 設定為 eagain)。此時程序沒有拿到需要的資料。那怎麼辦?
有兩種辦法。
因為程序沒辦法知道資料什麼時候才真正讀取完畢了,所以需要每隔一段時間就去輪詢一下(就是重新呼叫 read,看是不是資料真的已經讀取完畢了)。
大部分場景中都不會使用這種方式。但在某些特殊的情況下效率會特別高。
早期的非同步實現方式是核心給程序發訊號(sigio 或者 sigpoll)。資料讀寫完畢後,核心發訊號給程序,然後程序內的訊號處理函式再呼叫 read 讀取資料(這時可以確保資料真的已經讀取完畢了)。但這種方式有乙個小小的瑕疵,就是在程序進行多個 fd 讀寫的時候,訊號來的時候沒辦法分清到底是哪個 fd 上的資料已經真正準備好了。所以程序還是要對所有持有的 fd 進行 read 呼叫。
後來的非同步實現,就有了更好的 select / poll / epoll(i/o multiplexing)。現在基本上像比較流行的 nginx / redis 都用 epoll(在 freebsd 上是 kqueue)
阻塞式i/o模型:預設情況下,所有套接字都是阻塞的。怎麼理解?先理解這麼個流程,乙個輸入操作通常包括兩個不同階段:
(1)等待資料準備好;
(2)從核心向程序複製資料。
對於乙個套接字上的輸入操作,第一步通常涉及等待資料從網路中到達。當所有等待分組到達時,它被複製到核心中的某個緩衝區。第二步就是把資料從核心緩衝區複製到應用程式緩衝區。 好,下面我們以阻塞套接字的recvfrom的的呼叫圖來說明阻塞
標紅的這部分過程就是阻塞,直到阻塞結束recvfrom才能返回。
非阻塞式i/o: 以下這句話很重要:程序把乙個套接字設定成非阻塞是在通知核心,當所請求的i/o操作非得把本程序投入睡眠才能完成時,
不要把程序投入睡眠,而是返回乙個錯誤。看看非阻塞的套接字的recvfrom操作如何進行
可以看出recvfrom總是立即返回。
i/o多路復用:雖然i/o多路復用的函式也是阻塞的,但是其與以上兩種還是有不同的,i/o多路復用是阻塞在select,epoll這樣的系統呼叫之上,
而沒有阻塞在真正的i/o系統呼叫如recvfrom之上。如圖
訊號驅動式i/o:用的很少,就不做講解了。直接上圖
非同步i/o:這類函式的工作機制是告知核心啟動某個操作,並讓核心在整個操作(包括將資料從核心拷貝到使用者空間)完成後通知我們。如圖:
注意紅線標記處說明在呼叫時就可以立馬返回,等函式操作完成會通知我們
例子一:
乙個網路包從應用程式a發到另一台電腦上的應用程式b,需要經歷:
從a的業務**到a的軟體框架
從a的軟體框架到計算機的作業系統核心
從a所在計算機的核心到網絡卡
從網絡卡經過網線發到交換機等裝置,層層**,到達b所在計算機的網絡卡
從b所在計算機的網絡卡到b所在計算機的核心
從b所在計算機的核心到b的程式的使用者空間
從b的軟體框架到b的業務**
例子二:
小樂愛喝茶,廢話不說,煮開水。
出場人物:小樂,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。
1 小樂把水壺放到火上,立等水開。(同步阻塞)
—— 小樂覺得自己有點傻
2 小樂把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。(同步非阻塞)
—— 小樂還是覺得自己有點傻,於是變高階了,買了把會響笛的那種水壺。水開之後,能大聲發出嗚嗚~~~~的噪音。
3 小樂把響水壺放到火上,立等水開。(非同步阻塞)
—— 小樂覺得這樣傻等意義不大
4 小樂把響水壺放到火上,去客廳看電視,水壺響之前不再去看它了,響了再去拿壺。(非同步非阻塞)
—— 小樂覺得自己聰明了。
所謂同步非同步,只是對於水壺而言。
普通水壺,同步;響水壺,非同步。
雖然都能幹活,但響水壺可以在自己完工之後,提示小樂水開了。這是普通水壺所不能及的。
同步只能讓呼叫者去輪詢自己(情況2中),造成小樂效率的低下。
所謂阻塞非阻塞,僅僅對於小樂而言。
—— 立等的小樂,阻塞;看電視的小樂,非阻塞。
情況1和情況3中小樂就是阻塞的,媳婦喊他都不知道。
雖然3中響水壺是非同步的,可對於立等的小樂沒有太大的意義。
所以一般非同步是配合非阻塞使用的,這樣才能發揮非同步的效用。
阻塞式 非阻塞式IO
知識點 非阻塞式io 的兩種設定方法 1 函式fcntl 設定 o nonblock 選項 int flag fcntl sockfd,f getfl,0 檢查檔案標誌位 fcntl sockfd,f setfl,flag o nonblock 設定檔案標誌位 2 函式ioctl 設定fionbio...
Java IO 阻塞 非阻塞式IO 同步 非同步IO
同步 synchronous io和非同步 asynchronous io,阻塞 blocking io和非阻塞 non blocking io分別是什麼,到底有什麼區別?這個問題其實不同的人給出的答案都可能不同,比如wiki,就認為asynchronous io和non blocking io是乙...
linux裝置驅動之阻塞與非阻塞I 0
一 基本概念 阻塞操作是指在執行裝置操作時,若不能獲取資源,則掛起當前程序,直到滿足可操作的條件再進行操作。掛起的程序放到等待佇列,當條件滿足時,恢復執行。非阻塞操作是指當執行裝置操作時,若不能獲取資源,則立刻返回,不等待。二 阻塞i o 阻塞i o的是用等待佇列實現的。乙個程序的i o操作被阻塞時...