IO中同步 非同步與阻塞 非阻塞的區別

2022-06-27 18:39:10 字數 4363 閱讀 6684

一、同步與非同步

同步/非同步, 它們是訊息的通知機制

1. 概念解釋

a. 同步

所謂同步,就是在發出乙個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。

按照這個定義,其實絕大多數函式都是同步呼叫(例如sin isdigit等)。

但是一般而言,我們在說同步、非同步的時候,特指那些需要其他部件協作或者需要一定時間完成的任務。

最常見的例子就是 sendmessage。

該函式傳送乙個訊息給某個視窗,在對方處理完訊息之前,這個函式不返回。

當對方處理完畢以後,該函式才把訊息處理函式所返回的值返回給呼叫者。

b. 非同步

非同步的概念和同步相對。

當乙個非同步過程呼叫發出後,呼叫者不會立刻得到結果。

實際處理這個呼叫的部件是在呼叫發出後,

通過狀態、通知來通知呼叫者,或通過**函式處理這個呼叫。

以 socket為例,

當乙個客戶端通過呼叫 connect函式發出乙個連線請求後,呼叫者執行緒不用等待結果,可立刻繼續向下執行。

當連線真正建立起來以後,socket底層會傳送乙個訊息通知該物件。

c. 三種返回結果途徑 

執行部件和呼叫者可以通過三種途徑返回結果:

a.   狀態、

b.   通知、

c.   **函式。

可以使用哪一種依賴於執行部件的實現,除非執行部件提供多種選擇,否則不受呼叫者控制。

a. 如果執行部件用狀態來通知,

那麼呼叫者就需要每隔一定時間檢查一次,效率就很低

有些初學多執行緒程式設計的人,總喜歡用乙個迴圈去檢查某個變數的值,這其實是一種很嚴重的錯誤。

b. 如果是使用通知的方式,

效率則很高,因為執行部件幾乎不需要做額外的操作。

c. 至於**函式,

和通知沒太多區別。

2. 舉例說明

理解這兩個概念,可以用去銀行辦理業務(可以取錢,也可以存錢)來比喻:

當到銀行後,

.可以去atm機前排隊等候                                -- (排隊等候)就是同步等待訊息

.可以去大廳拿號,等到排到我的號時,

櫃檯的人會通知我輪到我去辦理業務.              -- (等待別人通知)就是非同步等待訊息.

在非同步訊息通知機制中,

等待訊息者(在這個例子中就是等待辦理業務的人)往往註冊乙個**機制,

在所等待的事件被觸發時由觸發機制(在這裡是櫃檯的人)通過某種機制(在這裡是寫在小紙條上的號碼)

找到等待該事件的人.

在select/poll 等io 多路復用機制中就是fd,

當訊息被觸發時,觸發機制通過fd 找到處理該fd的處理函式.

3. 在實際的程式中,

同步訊息通知機制:就好比簡單的read/write 操作,它們需要等待這兩個操作成功才能返回;

同步, 是由處理訊息者自己去等待訊息是否被觸發;

非同步訊息通知機制:類似於select/poll 之類的多路復用io 操作,

當所關注的訊息被觸發時,由訊息觸發機制通知觸發對訊息的處理.

非同步, 由觸發機制來通知處理訊息者;

還是回到上面的例子,

輪到你辦理業務, 這個就是你關注的訊息,

而辦理什麼業務, 就是對這個訊息的處理,

兩者是有區別的.

而在真實的io 操作時: 所關注的訊息就是     該fd是否可讀寫,

而對訊息的處理是     對這個fd 進行讀寫.

同步/非同步僅僅關注的是如何通知訊息,它們對如何處理訊息並不關心,

好比說,銀行的人僅僅通知你輪到你辦理業務了,

而辦理業務什麼業務(存錢還是取錢)他們是不知道的.

二、阻塞與非阻塞

阻塞/非阻塞, 它們是程式在等待訊息(無所謂同步或者非同步)時的狀態.

1. 概念解釋

a. 阻塞

阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。函式只有在得到結果之後才會返回。

有人也許會把阻塞呼叫和同步呼叫等同起來,實際上他是不同的。

對於同步呼叫來說,很多時候當前執行緒還是啟用的,只是從邏輯上當前函式沒有返回而已。

socket接收資料函式recv是乙個阻塞呼叫的例子。

當socket工作在阻塞模式的時候, 如果沒有資料的情況下呼叫該函式,則當前執行緒就會被掛起,直到有資料為止。

b. 非阻塞

非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函式不會阻塞當前執行緒,而會立刻返回。

c. 物件的阻塞模式和阻塞函式呼叫

物件是否處於阻塞模式和函式是不是阻塞呼叫有很強的相關性,但是並不是一一對應的。

阻塞物件上可以有非阻塞的呼叫方式,我們可以通過一定的api去輪詢狀態,

在適當的時候呼叫阻塞函式,就可以避免阻塞。

而對於非阻塞物件,呼叫特殊的函式也可以進入阻塞呼叫。函式select就是這樣的乙個例子。

2. 舉例說明

繼續上面的那個例子,

不論是排隊等待,還是使用號碼等待通知,

如果在這個等待的過程中,

. 等待者除了等待訊息之外不能做其它的事情,那麼該機制就是阻塞的,

表現在程式中,也就是該程式一直阻塞在該函式呼叫處不能繼續往下執行.

. 相反,有的人喜歡在銀行辦理這些業務的時候一邊打打**發發簡訊一邊等待,這樣的狀態就是非阻塞的,

因為他(等待者)沒有阻塞在這個訊息通知上,而是一邊做自己的事情一邊等待.

三、易混淆的點

很多人也會把非同步和非阻塞混淆,

因為非同步操作一般都不會在真正的io 操作處被阻塞,

比如如果用select 函式,當select 返回可讀時再去read 一般都不會被阻塞

就好比當你的號碼排到時一般都是在你之前已經沒有人了,所以你再去櫃檯辦理業務就不會被阻塞.

可見,同步/非同步與阻塞/非阻塞是兩組不同的概念,它們可以共存組合,

而很多人之所以把同步和阻塞混淆,我想也是因為沒有區分這兩個概念,

比如阻塞的read/write 操作中,其實是把訊息通知和處理訊息結合在了一起,

在這裡所關注的訊息就是fd 是否可讀/寫,而處理訊息則是對fd 讀/寫.

當我們將這個fd 設定為非阻塞的時候,read/write 操作就不會在等待訊息通知這裡阻塞,

如果fd 不可讀/寫則操作立即返回.

四、同步/非同步與阻塞/非阻塞的組合分析

_______阻塞____________________非阻塞_____

同步 | 同步阻塞              同步非阻塞

非同步 | 非同步阻塞              非同步非阻塞

同步阻塞形式:

效率是最低的,

拿上面的例子來說,就是你專心排隊,什麼別的事都不做。

實際程式中

就是未對fd 設定o_nonblock 標誌位的read/write 操作,

非同步阻塞形式:

如果在銀行等待辦理業務的人採用的是非同步的方式去等待訊息被觸發,也就是領了一張小紙條,

假如在這段時間裡他不能離開銀行做其它的事情,那麼很顯然,這個人被阻塞在了這個等待的操作上面;

非同步操作是可以被阻塞住的,只不過它不是在處理訊息時阻塞,而是在等待訊息被觸發時被阻塞.

比如select 函式,

假如傳入的最後乙個timeout 引數為null,那麼如果所關注的事件沒有乙個被觸發,

程式就會一直阻塞在這個select 呼叫處.

同步非阻塞形式:

實際上是效率低下的,

想象一下你一邊打著**一邊還需要抬頭看到底隊伍排到你了沒有,

如果把打**和觀察排隊的位置看成是程式的兩個操作的話,

這個程式需要在這兩種不同的行為之間來回的切換,效率可想而知是低下的;

很多人會寫阻塞的read/write 操作,

但是別忘了可以對fd 設定o_nonblock 標誌位,這樣就可以將同步操作變成非阻塞的了;

非同步非阻塞形式:

效率更高,

因為打**是你(等待者)的事情,而通知你則是櫃檯(訊息觸發機制)的事情,

程式沒有在兩種不同的操作中來回切換.

比如說,這個人突然發覺自己菸癮犯了,需要出去抽根菸,

於是他告訴大堂經理說,排到我這個號碼的時候麻煩到外面通知我一下(註冊乙個**函式),

那麼他就沒有被阻塞在這個等待的操作上面,自然這個就是非同步+非阻塞的方式了.

如果使用非同步非阻塞的情況,

比如aio_*組的操作,當發起乙個aio_read 操作時,函式會馬上返回不會被阻塞,

當所關注的事件被觸發時會呼叫之前註冊的**函式進行處理,

IO 同步,非同步,阻塞,非阻塞

參考文章 好文推薦 唉最近真是高產似母豬,剛進新公司工作量暫時不飽和,只能每天學學學學學學查漏補缺啦,學習使我快樂哈哈哈哈哈哈哈哈 標題裡的詞彙相信都經常看到,但是能說清楚的估計20個人裡面能有1個就不錯了,網上的資料也是五花八門,大部分描述差不多,很多時候估計作者本身也是似懂非懂,我也看了很多文章...

同步 非同步 阻塞 非阻塞 I O

一 同步 非同步 首先要是多個事物,只有乙個事物,是不存在同步或非同步的。同步 指協同步調。即,多個事物不能同時進行,必須乙個乙個的來,上乙個事物結束後,下乙個事物才開始。那當乙個事物正在進行時,其他事物在幹嘛呢?嚴格來講並沒有要求,但一般都處於 等待 狀態,因為後面事物的正常進行都需要依賴前面事物...

同步非同步IO,阻塞非阻塞

同步io操作 導致請求程序阻塞,知道io操作完成。非同步io操作 不導致程序阻塞。在處理 網路 io 的時候,阻塞和非阻塞都是同步io,阻塞,就是呼叫我 函式 我 函式 沒有接收完資料或者沒有得到結果之前,我不會返回。非阻塞,就是呼叫我 函式 我 函式 立即返回,通過select通知呼叫者 阻塞與非...