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

IO中同步、異步與阻塞、非阻塞的區別html


標籤:異步同步 阻塞非阻塞git

1、同步與異步
同步/異步, 它們是消息的通知機制編程

1. 概念解釋
A. 同步
所謂同步,就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不返回。多線程

按照這個定義,其實絕大多數函數都是同步調用(例如sin isdigit等)。
可是通常而言,咱們在說同步、異步的時候,特指那些須要其餘部件協做或者須要必定時間完成的任務。
最多見的例子就是 SendMessage。
該函數發送一個消息給某個窗口,在對方處理完消息以前,這個函數不返回。
當對方處理完畢之後,該函數才把消息處理函數所返回的值返回給調用者。異步

B. 異步
異步的概念和同步相對。
當一個異步過程調用發出後,調用者不會馬上獲得結果。
實際處理這個調用的部件是在調用發出後,
經過狀態、通知來通知調用者,或經過回調函數處理這個調用。socket

以 Socket爲例,
當一個客戶端經過調用 Connect函數發出一個鏈接請求後,調用者線程不用等待結果,可馬上繼續向下運行。
當鏈接真正創建起來之後,socket底層會發送一個消息通知該對象。async

C. 三種返回結果途徑
執行部件和調用者能夠經過三種途徑返回結果:
a.   狀態、
b.   通知、
c.   回調函數。分佈式

可使用哪種依賴於執行部件的實現,除非執行部件提供多種選擇,不然不受調用者控制。ide

a. 若是執行部件用狀態來通知,
那麼調用者就須要每隔必定時間檢查一次,效率就很低
有些初學多線程編程的人,總喜歡用一個循環去檢查某個變量的值,這實際上是一種很嚴重的錯誤。異步編程

b. 若是是使用通知的方式,
效率則很高,由於執行部件幾乎不須要作額外的操做。

c. 至於回調函數,
和通知沒太多區別。

2. 舉例說明
理解這兩個概念,能夠用去銀行辦理業務(能夠取錢,也能夠存錢)來比喻:
當到銀行後,
.能夠去ATM機前排隊等候                                – (排隊等候)就是同步等待消息
.能夠去大廳拿號,等到排到個人號時,
櫃檯的人會通知我輪到我去辦理業務.              – (等待別人通知)就是異步等待消息.

在異步消息通知機制中,
等待消息者(在這個例子中就是等待辦理業務的人)每每註冊一個回調機制,
在所等待的事件被觸發時由觸發機制(在這裏是櫃檯的人)經過某種機制(在這裏是寫在小紙條上的號碼)
找到等待該事件的人.

在select/poll 等IO 多路複用機制中就是fd,
當消息被觸發時,觸發機制經過fd 找處處理該fd的處理函數.

3. 在實際的程序中,
同步消息通知機制:就比如簡單的read/write 操做,它們須要等待這兩個操做成功才能返回;
同步, 是由處理消息者本身去等待消息是否被觸發;
異步消息通知機制:相似於select/poll 之類的多路複用IO 操做,
當所關注的消息被觸發時,由消息觸發機制通知觸發對消息的處理.
異步, 由觸發機制來通知處理消息者;

仍是回到上面的例子,
輪到你辦理業務, 這個就是你關注的消息,
而辦理什麼業務, 就是對這個消息的處理,
二者是有區別的.

而在真實的IO 操做時: 所關注的消息就是     該fd是否可讀寫,
而對消息的處理是     對這個fd 進行讀寫.

同步/異步僅僅關注的是如何通知消息,它們對如何處理消息並不關心,
比如說,銀行的人僅僅通知你輪到你辦理業務了,
而辦理業務什麼業務(存錢仍是取錢)他們是不知道的.

2、阻塞與非阻塞
阻塞/非阻塞, 它們是程序在等待消息(無所謂同步或者異步)時的狀態.

1. 概念解釋
A. 阻塞
阻塞調用是指調用結果返回以前,當前線程會被掛起。函數只有在獲得結果以後纔會返回。
有人也許會把阻塞調用和同步調用等同起來,實際上他是不一樣的。
對於同步調用來講,不少時候當前線程仍是激活的,只是從邏輯上當前函數沒有返回而已。

socket接收數據函數recv是一個阻塞調用的例子。
當socket工做在阻塞模式的時候, 若是沒有數據的狀況下調用該函數,則當前線程就會被掛起,直到有數據爲止。

B. 非阻塞
非阻塞和阻塞的概念相對應,指在不能馬上獲得結果以前,該函數不會阻塞當前線程,而會馬上返回。

C. 對象的阻塞模式和阻塞函數調用
對象是否處於阻塞模式和函數是否是阻塞調用有很強的相關性,可是並非一一對應的。

阻塞對象上能夠有非阻塞的調用方式,咱們能夠經過必定的API去輪詢狀態,
在適當的時候調用阻塞函數,就能夠避免阻塞。
而對於非阻塞對象,調用特殊的函數也能夠進入阻塞調用。函數select就是這樣的一個例子。

2. 舉例說明
繼續上面的那個例子,
不管是排隊等待,仍是使用號碼等待通知,
若是在這個等待的過程當中,
. 等待者除了等待消息以外不能作其它的事情,那麼該機制就是阻塞的,
表如今程序中,也就是該程序一直阻塞在該函數調用處不能繼續往下執行.
. 相反,有的人喜歡在銀行辦理這些業務的時候一邊打打電話發發短信一邊等待,這樣的狀態就是非阻塞的,
由於他(等待者)沒有阻塞在這個消息通知上,而是一邊作本身的事情一邊等待.

3、易混淆的點
不少人也會把異步和非阻塞混淆,
由於異步操做通常都不會在真正的IO 操做處被阻塞,
好比若是用select 函數,當select 返回可讀時再去read 通常都不會被阻塞
就比如當你的號碼排到時通常都是在你以前已經沒有人了,因此你再去櫃檯辦理業務就不會被阻塞.
可見,同步/異步與阻塞/非阻塞是兩組不一樣的概念,它們能夠共存組合,

而不少人之因此把同步和阻塞混淆,我想也是由於沒有區分這兩個概念,
好比阻塞的read/write 操做中,實際上是把消息通知和處理消息結合在了一塊兒,
在這裏所關注的消息就是fd 是否可讀/寫,而處理消息則是對fd 讀/寫.
當咱們將這個fd 設置爲非阻塞的時候,read/write 操做就不會在等待消息通知這裏阻塞,
若是fd 不可讀/寫則操做當即返回.

4、同步/異步與阻塞/非阻塞的組合分析
_______阻塞____________________非阻塞_____
同步 | 同步阻塞              同步非阻塞
異步 | 異步阻塞              異步非阻塞

同步阻塞形式:
效率是最低的,
拿上面的例子來講,就是你專心排隊,什麼別的事都不作。

實際程序中
就是未對fd 設置O_NONBLOCK 標誌位的read/write 操做,

異步阻塞形式:
若是在銀行等待辦理業務的人採用的是異步的方式去等待消息被觸發,也就是領了一張小紙條,
假如在這段時間裏他不能離開銀行作其它的事情,那麼很顯然,這我的被阻塞在了這個等待的操做上面;

異步操做是能夠被阻塞住的,只不過它不是在處理消息時阻塞,而是在等待消息被觸發時被阻塞.
好比select 函數,
假如傳入的最後一個timeout 參數爲NULL,那麼若是所關注的事件沒有一個被觸發,
程序就會一直阻塞在這個select 調用處.

同步非阻塞形式:
其實是效率低下的,
想象一下你一邊打着電話一邊還須要擡頭看到底隊伍排到你了沒有,
若是把打電話和觀察排隊的位置當作是程序的兩個操做的話,
這個程序須要在這兩種不一樣的行爲之間來回的切換,效率可想而知是低下的;

不少人會寫阻塞的read/write 操做,
可是別忘了能夠對fd 設置O_NONBLOCK 標誌位,這樣就能夠將同步操做變成非阻塞的了;

異步非阻塞形式:
效率更高,
由於打電話是你(等待者)的事情,而通知你則是櫃檯(消息觸發機制)的事情,
程序沒有在兩種不一樣的操做中來回切換.

好比說,這我的忽然發覺本身煙癮犯了,須要出去抽根菸,
因而他告訴大堂經理說,排到我這個號碼的時候麻煩到外面通知我一下(註冊一個回調函數),
那麼他就沒有被阻塞在這個等待的操做上面,天然這個就是異步+非阻塞的方式了.

若是使用異步非阻塞的狀況,
好比aio_*組的操做,當發起一個aio_read 操做時,函數會立刻返回不會被阻塞,
當所關注的事件被觸發時會調用以前註冊的回調函數進行處理,

下面再轉載知乎中「怎樣理解阻塞非阻塞與同步異步的區別?」這個問題的答案

  • 盧伊愛好者

    「阻塞」與」非阻塞」與」同步」與「異步」不能簡單的從字面理解,提供一個從分佈式系統角度的回答。
    1.同步與異步
    同步和異步關注的是消息通訊機制 (synchronous communication/ asynchronous communication)
    所謂同步,就是在發出一個*調用*時,在沒有獲得結果以前,該*調用*就不返回。可是一旦調用返回,就獲得返回值了。
    換句話說,就是由*調用者*主動等待這個*調用*的結果。而異步則是相反,*調用*在發出以後,這個調用就直接返回了,因此沒有返回結果。換句話說,當一個異步過程調用發出後,調用者不會馬上獲得結果。而是在*調用*發出後,*被調用者*經過狀態、通知來通知調用者,或經過回調函數處理這個調用。


    典型的異步編程模型好比Node.js

    舉個通俗的例子:
    你打電話問書店老闆有沒有《分佈式系統》這本書,若是是同步通訊機制,書店老闆會說,你稍等,」我查一下」,而後開始查啊查,等查好了(多是5秒,也多是一天)告訴你結果。
    而異步通訊機制,書店老闆直接告訴你我查一下啊(返回值),查好了打電話給你,而後直接掛電話了。而後查好了,他會主動打電話給你。在這裏老闆經過「回電」這種方式來回調。

    2. 阻塞與非阻塞
    阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態.

    阻塞調用是指調用結果返回以前,當前線程會被掛起。調用線程只有在獲得結果以後纔會返回。
    非阻塞調用指在不能馬上獲得結果以前,該調用不會阻塞當前線程。

    仍是上面的例子,
    你打電話問書店老闆有沒有《分佈式系統》這本書,你若是是阻塞式調用,你會一直把本身「掛起」,直到獲得這本書有沒有的結果,若是是非阻塞式調用,你無論老闆有沒有告訴你,你本身先一邊去玩了, 固然你也要偶爾過幾分鐘check一下老闆有沒有返回結果。
    在這裏阻塞與非阻塞與是否同步異步無關。跟老闆經過什麼方式回答你結果無關。

    若是是關心blocking IO/ asynchronous IO, 參考 Unix Network Programming View Book

  • 看看steven大叔的這篇文章。http://english.tebyan.net/newindex.aspx?pid=31159&BookID=23760&PageIndex=92&Language=3
    同步和異步僅僅是關於所關注的消息如何通知的機制。同步的狀況下,是由處理消息者本身去等待消息是否被觸發,而異步的狀況下是由觸發機制來通知處理消息者
    阻塞和非阻塞應該是發生在消息的處理的時刻。阻塞其實就是等待,發出通知,等待結果完成。非阻塞屬於發出通知,當即返回結果,沒有等待過程。



原文:http://www.jsxubar.info/io-sync-async.html

相關文章
相關標籤/搜索