java - 同步/非同步與阻塞/非阻塞之間的差異具體是什麼?
怪我咯
怪我咯 2017-05-17 10:08:42
0
4
926

就我的理解,同步/阻塞是同一概念,都是客戶端等待服務端的回執,服務端不返回回執,客戶端就不往下走;而異步/非阻塞則是客戶端不等待服務端的回執,直接往下走,等到服務端處理結束後,在呼叫非同步回呼函數通知客戶端。

但具體的,同步和阻塞,非同步和非阻塞間的區別,分不清,有誰能解惑呢?

怪我咯
怪我咯

走同样的路,发现不同的人生

全部回覆(4)
習慣沉默

推薦一篇部落格文章聊聊Linux 五種IO模型,寫的很不錯。簡要的跟你說下這幾個。
首先,只有同步才有所謂的阻塞非阻塞,非同步並沒有。常規的錯誤理解是,我們覺得非同步就是非阻塞的,然而並不是這樣的。這裡的同步與非同步的差別就是,對於一個網路IO或磁碟IO的「整個過程」有沒有存在阻塞,是整個過程。
以一次read的系統呼叫為例子,作為一個使用者線程,當你發起一次read的系統呼叫的時候,可以分成兩個操作,

  • 一是資料讀取:把資料從磁碟讀到核心空間,我們都知道,read屬於系統調用,使用者級執行緒是無法操作的,只能交給核心執行緒去處理,而核心執行緒首先要找到數據,並讀到內核空間。

  • 二是資料複製:把資料從核心空間讀取到用戶空間。然後用戶線程才可以使用這些數據。

所以簡單的說,

  • 同步就是上述兩個過程都阻塞了,你用戶線程一直在等。

  • 非阻塞就是上述第一個過程你沒有阻塞,但是用戶線程必須不斷的詢問os,資料是否從磁碟拷貝到內和空間了,如果拷貝好了,則在資料複製的過程阻塞。所以所有的同步過程,在第二階段都是阻塞的,儘管這是非阻塞的呼叫。

  • 多路復用:和非阻塞一樣,在第二階段也是阻塞的,但是第一階段不再由自己去詢問操作系統,而是統一交給一個內核線程去處理(linux上實現的有poll ,以及改進版的epoll),當你的資料讀取完成,這個線程就發送一個信號給原先發起系統調用的用戶線程,然後用戶線程就進入阻塞,並開始資料拷貝了。

  • 異步:上述兩個過程都是非阻塞的。

上述只是簡單描述,希望有幫助

PHPzhong

同步異步的概念主要是描述IO方面的。簡而言之同步和非同步的主要區別是通知呼叫程序或執行緒的方式,立即返回通知即同步,透過註冊回呼通知則是非同步。阻塞和非阻塞主要描述函數的呼叫返回情況。函數立即傳回即非阻塞,函數被掛起則阻塞。

舉個簡單類比場景,假如你去餐廳點餐。

同步阻塞

你跟訂餐員說要一份台灣牛肉麵,訂餐員聽見之後就去廚房,過了一會兒才拿出來給你。這段時間你就在前台傻傻的等著,沒有任何回复,什麼都不做(阻塞),你在下單之後沒有收到任何回复,一直等待的過程就是同步的通信。

同步非阻塞

你跟訂餐員說要一份蘭州牛肉麵,訂餐員回覆你說,估計要五分鐘。然後你想了一下,五分鐘可以刷一刷帖子,幹點別的事情解悶。但很快肚子餓,你每隔一分鐘就問一次好了沒,得到的回覆就是還沒好,直到5分鐘後,才拿到面。等待的過程中你沒有閒著,可以做別的事情,這是非阻塞。由於你還是主動詢問結果並等待訂餐員的回复,所以這還是同步的。

非同步阻塞與非阻塞

所謂異步,就是不需要你主動去詢問結果,而是註冊一個回呼函數。即你點餐完畢之後,訂餐員給了你一個號碼。旁邊有一個機器,輪到你的時候,機器就會叫號。通知你的這個過程叫異步,如果你在一旁坐著,啥也不乾,那你就是阻塞狀態。如果在一旁刷網頁,那就是非阻塞。

所以區別同步還是異步,主要在於訊息的通知方式,阻塞和非阻塞在於函數呼叫等待通知時的狀態,即是否掛起,以至於當前的線程或者進程,和還是能否繼續做別的。

通常也有一種協程式的方式來實現非同步非阻塞。也就是函數呼叫遇到IO的時候,註冊回呼函數後,就掛起返回,因為返回了,所以是非阻塞,然後等IO完成了,回調函數通知喚醒掛起的函數,此時就是非同步。

phpcn_u1582

一般來說阻塞和非阻塞式指IO呼叫是立即返回(非阻塞)還是等待完成再返回(阻塞)。同步和非同步是廣義概念,是阻塞和非阻塞的表現。

给我你的怀抱

其實你理解的很對,同步就是指不會出現資料的不統一,單執行緒是順序執行。不同步就是會出現資料不統一的現象,例如多執行緒的時候,這個執行緒用到的資料可能會被另一個執行緒給改了,就造成資料不同步了。而阻塞和非阻塞是指在執行緒運行的時候是否等待函數返回,如果是單執行緒就會一直等待,如果是多執行緒的就不等待向下執行這個時候就容易出現不同步的情況了。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板