同步、非同步、阻塞與非阻塞
1 同步與非同步
首先來解釋同步和非同步的概念,這兩個概念與訊息的通知機制有關。也就是同步與非同步主要是從訊息通知機制角度來說的。
1.1 概念描述
所謂同步就是一個任務的完成需要依賴另外一個任務時,只有等待被依賴的任務完成後, 依賴的任務才能算完成,這是一種可靠的任務序列。要麼成功都成功,失敗都失敗,兩個任務的狀態可以保持一致。
所謂非同步是不需要等待被依賴的任務完成,只是通知被依賴的任務要完成什麼工作, 依賴的任務也立即執行,只要自己完成了整個任務就算完成了。至於被依賴的任務最終是否真正完成,依賴它的任務無法確定,所以它是不可靠的任務序列。
1.2 訊息通知
非同步的概念和同步相對。當一個同步呼叫發出後,呼叫者要一直等待返回訊息(結果)通知後,才能進行後續的執行;當一個非同步過程呼叫發出後,呼叫者不能立刻得到返回訊息(結果)。實際處理這個呼叫的部件在完成後,通過狀態、通知和回撥來通知呼叫者。
這裡提到執行部件和呼叫者通過三種途徑返回結果:狀態、通知和回撥。使用哪一種通知機制,依賴於執行部件的實現,除非執行部件提供多種選擇,否則不受呼叫者控制。
如果執行部件用狀態來通知,那麼呼叫者就需要每隔一定時間檢查一次,效率就很低(有些初學多執行緒程式設計的人,總喜歡用一個迴圈去檢查某個變數的值,這其實是一種很嚴重的錯誤);
如果是使用通知的方式,效率則很高,因為執行部件幾乎不需要做額外的操作。至於回撥函式,其實和通知沒太多區別。
1.3 場景比喻
舉個例子,比如我去銀行辦理業務,可能會有兩種方式:
1. 選擇排隊等候;
2. 另種選擇取一個小紙條上面有我的號碼,等到排到我這一號時由櫃檯的人通知我輪到我去辦理業務了;
第一種:前者(排隊等候)就是同步等待訊息通知,也就是我要一直在等待銀行辦理業務情況;
第二種:後者(等待別人通知)就是非同步等待訊息通知。在非同步訊息處理中,等待訊息通知者(在這個例子中就是等待辦理業務的人)往往註冊一個回撥機制,在所等待的事件被觸發時由觸發機制(在這裡是櫃檯的人)通過某種機制(在這裡是寫在小紙條上的號碼,喊號)找到等待該事件的人。
2 阻塞與非阻塞
阻塞和非阻塞這兩個概念與程式(執行緒)等待訊息通知(無所謂同步或者非同步)時的狀態有關。也就是說阻塞與非阻塞主要是程式(執行緒)等待訊息通知時的狀態角度來說的。
2.1 概念描述
阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起,一直處於等待訊息通知,不能夠執行其他業務。 函式只有在得到結果之後才會返回。
有人也許會把阻塞呼叫和同步呼叫等同起來,實際上它們是不同的。
對於同步呼叫來說,很多時候當前執行緒可能還是啟用的,只是從邏輯上當前函式沒有返回而已,此時,這個執行緒可能也會處理其他的訊息。還有一點,在這裡先擴充套件下:
(a) 如果這個執行緒在等待當前函式返回時,仍在執行其他訊息處理,那這種情況就叫做同步非阻塞;
(b) 如果這個執行緒在等待當前函式返回時,沒有執行其他訊息處理,而是處於掛起等待狀態,那這種情況就叫做同步阻塞;
所以同步的實現方式會有兩種:同步阻塞、同步非阻塞;同理,非同步也會有兩種實現:非同步阻塞、非同步非阻塞;
對於阻塞呼叫來說,則當前執行緒就會被掛起等待當前函式返回;
非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函式不會阻塞當前執行緒,而會立刻返回。雖然表面上看非阻塞的方式可以明顯的提高CPU的利用率,但是也帶了另外一種後果就是系統的執行緒切換增加。增加的CPU執行時間能不能補償系統的切換成本需要好好評估。
2.2 場景比喻
繼續上面的那個例子,不論是排隊還是使用號碼等待通知,如果在這個等待的過程中,等待者除了等待訊息通知之外不能做其它的事情,那麼該機制就是阻塞的,表現在程式中,也就是該程式一直阻塞在該函式呼叫處不能繼續往下執行。
相反,有的人喜歡在銀行辦理這些業務的時候一邊打打電話發發簡訊一邊等待,這樣的狀態就是非阻塞的,因為他(等待者)沒有阻塞在這個訊息通知上,而是一邊做自己的事情一邊等待。
但是需要注意了,同步非阻塞形式實際上是效率低下的,想象一下你一邊打著電話一邊還需要抬頭看到底隊伍排到你了沒有。如果把打電話和觀察排隊的位置看成是程式的兩個操作的話,這個程式需要在這兩種不同的行為之間來回的切換,效率可想而知是低下的;而非同步非阻塞形式卻沒有這樣的問題,因為打電話是你(等待者)的事情,而通知你則是櫃檯(訊息觸發機制)的事情,程式沒有在兩種不同的操作中來回切換。
3 同步/非同步與阻塞/非阻塞
3.1 同步阻塞形式
效率是最低的,
拿上面的例子來說,就是你專心排隊,什麼別的事都不做。
實際程式中:就是未對fd 設定O_NONBLOCK標誌位的read/write 操作;
3.2 非同步阻塞形式
如果在銀行等待辦理業務的人採用的是非同步的方式去等待訊息被觸發(通知),也就是領了一張小紙條,假如在這段時間裡他不能離開銀行做其它的事情,那麼很顯然,這個人被阻塞在了這個等待的操作上面;
非同步操作是可以被阻塞住的,只不過它不是在處理訊息時阻塞,而是在等待訊息通知時被阻塞。
比如select 函式,假如傳入的最後一個timeout引數為NULL,那麼如果所關注的事件沒有一個被觸發,程式就會一直阻塞在這個select 呼叫處。
3.3 同步非阻塞形式
實際上是效率低下的,
想象一下你一邊打著電話一邊還需要抬頭看到底隊伍排到你了沒有,如果把打電話和觀察排隊的位置看成是程式的兩個操作的話,這個程式需要在這兩種不同的行為之間來回的切換,效率可想而知是低下的。
很多人會寫阻塞的read/write 操作,但是別忘了可以對fd設定O_NONBLOCK 標誌位,這樣就可以將同步操作變成非阻塞的了。
3.4 非同步非阻塞形式
效率更高,
因為打電話是你(等待者)的事情,而通知你則是櫃檯(訊息觸發機制)的事情,程式沒有在兩種不同的操作中來回切換。
比如說,這個人突然發覺自己煙癮犯了,需要出去抽根菸,於是他告訴大堂經理說,排到我這個號碼的時候麻煩到外面通知我一下(註冊一個回撥函式),那麼他就沒有被阻塞在這個等待的操作上面,自然這個就是非同步+非阻塞的方式了。
如果使用非同步非阻塞的情況,比如aio_*組的操作,當發起一個aio_read操作時,函式會馬上返回不會被阻塞,當所關注的事件被觸發時會呼叫之前註冊的回撥函式進行處理。
很多人會把同步和阻塞混淆,我想是因為很多時候同步操作會以阻塞的形式表現出來,比如很多人會寫阻塞的read/write操作,但是別忘了可以對fd設定O_NONBLOCK標誌位,這樣就可以將同步操作變成非阻塞的了。但最根本是因為沒有區分這兩個概念,比如阻塞的read/write操作中,其實是把訊息通知機制和等待訊息通知的狀態結合在了一起,在這裡所關注的訊息就是fd是否可讀/寫,而等待訊息通知的狀態則是對fd可讀/寫等待過程中程式(執行緒)的狀態。當我們將這個fd設定為非阻塞的時候,read/write操作就不會在等待訊息通知這裡阻塞,如果fd不可讀/寫則操作立即返回。
同樣的,很多人也會把非同步和非阻塞混淆,因為非同步操作一般都不會在真正的IO操作處被阻塞,比如如果用select函式,當select返回可讀時再去read一般都不會被阻塞,而是在select函式呼叫處阻塞。
4 小明的故事
對上面所講的概念再次進行一個場景梳理,上面已經明確說明,同步/非同步關注的是訊息通知的機制,而阻塞/非阻塞關注的是程式(執行緒)等待訊息通知時的狀態。以小明下載檔案打個比方,從這兩個關注點來再次說明這兩組概念,希望能夠更好的促進大家的理解。
4.1 同步阻塞:小明一直盯著下載進度條,到 100% 的時候就完成。
同步體現在:等待下載完成通知;
阻塞體現在:等待下載完成通知過程中,不能做其他任務處理;
4.2 同步非阻塞:小明提交下載任務後就去幹別的,每過一段時間就去瞄一眼進度條,看到 100% 就完成。
同步體現在:等待下載完成通知;
非阻塞體現在:等待下載完成通知過程中,去幹別的任務了,只是時不時會瞄一眼進度條;【小明必須要在兩個任務間切換,關注下載進度】
4.3 非同步阻塞:小明換了個有下載完成通知功能的軟體,下載完成就“叮”一聲。不過小明仍然一直等待“叮”的聲音(看起來很傻,不是嗎)。
非同步體現在:下載完成“叮”一聲通知;
阻塞體現在:等待下載完成“叮”一聲通知過程中,不能做其他任務處理;
4.4 非同步非阻塞:仍然是那個會“叮”一聲的下載軟體,小明提交下載任務後就去幹別的,聽到“叮”的一聲就知道完成了。
非同步體現在:下載完成“叮”一聲通知;
非阻塞體現在:等待下載完成“叮”一聲通知過程中,去幹別的任務了,只需要接收“叮”聲通知即可;【軟體處理下載任務,小明處理其他任務,不需關注進度,只需接收軟體“叮”聲通知,即可】
也就是說,同步/非同步是“下載完成訊息”通知的方式(機制),而阻塞/非阻塞則是在等待“下載完成訊息”通知過程中的狀態(能不能幹其他任務), 在不同的場景下,同步/非同步、阻塞/非阻塞的四種組合都有應用。
所以,綜上所述,同步和非同步僅僅是關注的訊息如何通知的機制,而阻塞與非阻塞關注的是等待訊息通知時的狀態。 也就是說,同步的情況下,是由處理訊息者自己去等待訊息是否被觸發,而非同步的情況下是由觸發機制來通知處理訊息者, 所以在非同步機制中,處理訊息者和觸發機制之間就需要一個連線的橋樑:
在銀行的例子中,這個橋樑就是小紙條上面的號碼。
在小明的例子中,這個橋樑就是軟體“叮”的聲音。
最後,請大家注意理解“訊息通知機制”和“等待訊息通知時的狀態”這兩個概念,這是理解四個概念的關鍵所在。
相關文章
- 同步非同步 與 阻塞非阻塞非同步
- 同步非同步,阻塞非阻塞非同步
- 非同步、同步、阻塞、非阻塞非同步
- 理解阻塞、非阻塞、同步、非同步非同步
- 同步、非同步,阻塞、非阻塞理解非同步
- 徹底搞懂同步非同步與阻塞非阻塞非同步
- socket阻塞與非阻塞,同步與非同步、I/O模型非同步模型
- 同步、非同步、阻塞、非阻塞的區別非同步
- 聊聊執行緒與程式 & 阻塞與非阻塞 & 同步與非同步執行緒非同步
- IO - 同步 非同步 阻塞 非阻塞的區別非同步
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- 怎樣理解阻塞非阻塞與同步非同步的區別?非同步
- java同步非阻塞IOJava
- 同步阻塞、同步非阻塞、多路複用的介紹
- 如何解讀 Java IO、NIO 中的同步阻塞與同步非阻塞?Java
- 大白話搞懂什麼是同步/非同步/阻塞/非阻塞非同步
- ♻️同步和非同步;並行和併發;阻塞和非阻塞非同步並行
- 一篇文章讀懂阻塞,非阻塞,同步,非同步非同步
- 程式與執行緒、同步與非同步、阻塞與非阻塞、併發與並行執行緒非同步並行
- 程式執行緒、同步非同步、阻塞非阻塞、併發並行執行緒非同步並行
- 併發-0-同步/非同步/阻塞/非阻塞/程式/執行緒非同步執行緒
- 對於同步、非同步、阻塞、非阻塞的幾點淺薄理解非同步
- 【死磕NIO】— 阻塞、非阻塞、同步、非同步,傻傻分不清楚非同步
- 對執行緒、協程和同步非同步、阻塞非阻塞的理解執行緒非同步
- 【OS】同步非同步/阻塞非阻塞、併發並行序列的區分非同步並行
- Java 非阻塞 IO 和非同步 IOJava非同步
- 非同步/同步,阻塞/非阻塞,單執行緒/多執行緒概念梳理非同步執行緒
- 阻塞IO與非阻塞IO
- 阻塞非阻塞和同步非同步的區分 參考一些書籍非同步
- 談談對不同I/O模型的理解 (阻塞/非阻塞IO,同步/非同步IO)模型非同步
- python中非同步非阻塞如何實現Python非同步
- 如何給女朋友解釋什麼是IO中的阻塞、非阻塞、同步、非同步?非同步
- IO模式和IO多路複用(阻塞IO、非阻塞IO、同步IO、非同步IO等概念)模式非同步
- 從同步原語看非阻塞同步以及Java中的應用Java
- 【linux】驅動-13-阻塞與非阻塞Linux
- 11、協程和io教程01 -- 併發 並行 同步 非同步 阻塞 非阻塞 以及 IO多路複用並行非同步
- tornado原理介紹及非同步非阻塞實現方式非同步
- IO通訊模型(二)同步非阻塞模式NIO(NonBlocking IO)模型模式BloC