歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 怎樣理解阻塞非阻塞與同步異步的區別?

怎樣理解阻塞非阻塞與同步異步的區別?

日期:2017/3/1 9:27:16   编辑:Linux編程

“阻塞”與"非阻塞"與"同步"與“異步"不能簡單的從字面理解,提供一個從分布式系統角度的回答。

1.同步與異步
同步和異步關注的是消息通信機制 (synchronous communication/ asynchronous communication)
所謂同步,就是在發出一個*調用*時,在沒有得到結果之前,該*調用*就不返回。但是一旦調用返回,就得到返回值了。
換句話說,就是由*調用者*主動等待這個*調用*的結果。

而異步則是相反,*調用*在發出之後,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出後,調用者不會立刻得到結果。而是在*調用*發出後,*被調用者*通過狀態、通知來通知調用者,或通過回調函數處理這個調用。

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

舉個通俗的例子:
你打電話問書店老板有沒有《分布式系統》這本書,如果是同步通信機制,書店老板會說,你稍等,”我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。
而異步通信機制,書店老板直接告訴你我查一下啊,查好了打電話給你,然後直接掛電話了(不返回結果)。然後查好了,他會主動打電話給你。在這裡老板通過“回電”這種方式來回調。

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

阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之後才會返回。
非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。

還是上面的例子,
你打電話問書店老板有沒有《分布式系統》這本書,你如果是阻塞式調用,你會一直把自己“掛起”,直到得到這本書有沒有的結果,如果是非阻塞式調用,你不管老板有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鐘check一下老板有沒有返回結果。
在這裡阻塞與非阻塞與是否同步異步無關。跟老板通過什麼方式回答你結果無關。

在處理 IO 的時候,阻塞和非阻塞都是同步 IO。
只有使用了特殊的 API 才是異步 IO。

對unix來講:阻塞式I/O(默認),非阻塞式I/O(nonblock),I/O復用(select/poll/epoll)都屬於同步I/O,因為它們在數據由內核空間復制回進程緩沖區時都是阻塞的(不能干別的事)。只有異步I/O模型(AIO)是符合異步I/O操作的含義的,即在1數據准備完成、2由內核空間拷貝回緩沖區後 通知進程,在等待通知的。

以Linux下 tcp socket編程為例:

阻塞就是 recv/read的時候 socket接收緩沖區要是有數據就讀, 沒數據我就一直睡覺賴著不走,直到有數據來了讀完我才走。send/write的時候,要是發送緩沖區滿了,沒有空間繼續發送了我也一直睡覺賴著不走,直到發送緩沖區騰出足夠的空間讓我把數據全部塞到發送緩沖區裡我才走。(當然如果你通過setsockopt設置了讀寫超時,超時時間到了還是會返回-1和EAGAIN,不再睡覺等待)

各一句話
IO時進入內核代碼沒有立即返回,則直到返回前用戶的進程代碼一直處於「阻塞」狀態。
從IO請求到數據復制到進程空間的過程中,若進程代碼發生過阻塞,則IO過程是「同步」的,反之「異步」。

同步和異步僅僅是關於所關注的消息如何通知的機制。同步的情況下,是由處理消息者自己去等待消息是否被觸發,而異步的情況下是由觸發機制來通知處理消息者
阻塞和非阻塞應該是發生在消息的處理的時刻。阻塞其實就是等待,發出通知,等待結果完成。非阻塞屬於發出通知,立即返回結果,沒有等待過程。

關於同步異步、阻塞非阻塞的概念: 同步就是同步,異步就是異步! 目前應用中阻塞和非阻塞是針對同步應用而言。關於這些概念之間的關系的理解,可以通過以下幾個例子來說明。

例子1:老板布置了一個調研任務,老板自己需要寫一個調研報告。這個調研的一個子任務由同學A完成,老板最終需要將同學A的任務整合到自己的調研報告中。因為老板的調研報告需要用到同學A的調研結果,那麼老板的調研報告就必須等到同學A調研完成以後才能完成。那麼在整個調研的過程中,最終的調研報告和同學A的調研任務之間就是同步關系,因為兩個任務之間有著時序的關系。

首先一個IO操作其實分成了兩個步驟:發起IO請求和實際的IO操作,同步IO和異步IO的區別就在於第二個步驟是否阻塞,如果實際的IO讀寫阻塞請求進程,那麼就是同步IO,因此阻塞IO、非阻塞IO、IO服用、信號驅動IO都是同步IO,如果不阻塞,而是操作系統幫你做完IO操作再將結果返回給你,那麼就是異步IO。阻塞IO和非阻塞IO的區別在於第一步,發起IO請求是否會被阻塞,如果阻塞直到完成那麼就是傳統的阻塞IO,如果不阻塞,那麼就是非阻塞IO。

看了一些這兩個概念的解釋,感覺不分場景的籠統理解是不對的,下面陳述一下我的理解:

這是兩對概念,用在不同的語境會有一些不同的含義,不能一概而論。

整體來說,同步就是兩種東西通過一種機制實現步調一致,異步是兩種東西不必步調一致。

一、同步調用與異步調用:

在用在調用場景中,無非是對調用結果的不同處理。

我理解同步調用就是調用一但返回,就能知道結果,而異步是返回時不一定知道結果,還得通過其他機制來獲知結果,如:

a. 狀態

b. 通知

c. 回調函數

這裡的同步調用不一定會阻塞,例如立即返回失敗的結果。

而異步調用立即返回時,你還拿不到結果的。

二、同步線程與異步線程:

同步線程:即兩個線程步調要一致,要相互協商。兩個線程的運行進度各不相同,怎麼才能步調一致呢?我們直觀的理解就是,快的等慢的呗!快的阻塞一下等到慢的步調一致即可。

異步線程:步調不用一致,各自按各自的步調運行,不受另一個線程的影響。

同步是指兩個線程的運行是相關的,其中一個線程可能要阻塞等待另外一個線程的運行;

異步的意思是兩個線程毫無相關,自己運行自己的。

三、同步通信與異步通信:

這裡的同步和異步是指:發送方和接收方是否協調步調一致!

同步通信是指:發送方和接收方通過一定機制,實現收發步調協調。如:發送方發出數據後,等接收方發回響應以後才發下一個數據包的通訊方式

異步通信是指:發送方的發送不管接收方的接收狀態,如:發送方發出數據後,不等接收方發回響應,接著發送下個數據包的通訊方式。

阻塞和非阻塞就比較容易理解了,沒有上面那麼多場景,阻塞就是這個事情阻到這兒了,不能繼續往下干事了,非阻塞就是這個事情不會阻礙你繼續干後面的事情。

阻塞可以是實現同步的一種手段!例如兩個東西需要同步,一旦出現不同步情況,我就阻塞快的一方,使雙方達到同步。

同步是兩個對象之間的關系,而阻塞是一個對象的狀態。

Copyright © Linux教程網 All Rights Reserved