天天看點

舉例說明 同步 異步 阻塞 非阻塞

有趣的小栗子?

一個小故事

故事:小A燒開水。

出場人物:小A出場道具:普通水壺(放在瓦斯竈上的那種,為了友善簡稱:水壺);會響的水壺(水燒開了會響的那種,簡稱:響壺)。故事目的:小A要拿開水泡咖啡

小A為了實作目的,指定了4個計劃:

1、用水壺燒水,并且站在瓦斯竈旁邊,啥事不幹,兩眼直勾勾的盯着水壺,等水燒開。燒開後就去泡咖啡。同步阻塞

假設燒水和泡咖啡是在同一個線程中執行。

2、仍然用水壺煮水,不過此時不再傻傻得站在那裡看水開沒開,而是去玩局LOL,每當自己死了,就過來看看水開了沒有。如果水開了就去泡咖啡。同步非阻塞

假設這裡玩LOL,是另一個線程運作的。

3、動用響壺燒水,仍然站在瓦斯竈旁邊,不過此時不兩眼直勾勾的盯着壺了,而是聽響,因為響壺水開時會用響聲通知小A。異步阻塞

4、在計劃3的基礎上,小A不站在瓦斯竈旁邊了,而是去玩局LOL,等聽到響壺的聲音提醒後,再去跑咖啡。異步非阻塞

有了上邊的故事鋪墊,我們再來看一看概念

同步:

同步這個詞在很多場合下都會被使用,如果單從字面意思來看:相同的步驟。但是在程式設計的領域裡講,字面意思就不那麼準确了。

對于程式設計領域來說,同步就是發起一個請求,直到請求傳回結果之後,才進行下一步操作。簡單來說,同步就是必須一件事一件事的做,等前一件做完了,才能做下一件事。

例子:此種模式很常見,比如我發起一個網絡請求查詢一個人的身份證,然後根據身份證檢視這個人的詳細資訊。那麼我查詢詳細資訊的操作需要等待查詢身份證的操作,那麼此時查詢身份證的操作就是一個同步操作。

異步:

異步很明顯是與同步相對,二者的差別在于是否需要等待某操作的傳回結果。簡單來說,我們還是一個網絡請求,如果我們此時不需要依賴這個請求的結果就能進行後續操作,那麼此時這個網絡請求就是一個異步操作。

當一個異步操作發出後,調用者在沒有得到結果之前,可以繼續執行後續操作。這就是異步。

同步和異步的差別:

二者的差別還是很明顯的:請求發出後,是否需要等待請求結果,才能繼續執行其他操作。

阻塞

阻塞的概念往往伴随着線程。阻塞一般是指:在調用結果傳回之前,目前線程會被挂起。調用線程隻有在得到結果之後才會被喚醒執行後續的操作。

非阻塞

那麼非阻塞,毫無疑問是阻塞的反向操作。非阻塞式的調用指:在結果沒有傳回之前,該調用不會阻塞住目前線程。

是不是感覺阻塞/非阻塞和同步/異步有異曲同工的地方?

其實,這兩者存在本質的差別,面向的對象是不同的。

阻塞/非阻塞:程序/線程需要操作的資料如果尚未就緒,是否妨礙了目前程序/線程的後續操作。同步/異步:資料如果尚未就緒,是否需要等待資料結果。

并發和并行

二者的區分度非常的高,就在于四個字:是否同時。

并發:當有多個線程在操作時,如果系統隻有一個CPU,作業系統隻能把CPU運作時間劃分成若幹個時間段,再将時間段配置設定給各個線程執行,在一個時間段的快速的切換不同的線程代碼運作。

并行:當系統有多個CPU時,可以存在當一個CPU執行一個線程時,另一個CPU可以執行另一個線程,兩個線程互不搶占CPU資源,可以同時進行。

舉個小例子

小A吃飯吃到一半,電話來了,小A一直到吃完了以後才去接。既不支援并發也不支援并行

小A吃飯吃到一半,電話來了,小A停了下來接了電話,接完後繼續吃飯。支援并發

小A吃飯吃到一半,電話來了,小A一邊打電話一邊吃飯。支援并行

------------------------------------------------------------分割線-------------------------------------------------------------------

在面試中我們會碰到這種場景:

面試官:能解釋下什麼是同步,異步麼?

程式員:假如我們執行A,B兩個IO操作的時候,如果必須等待A完成後才能執行B那麼這個就是

同步的,如果A,B可以同時執行那麼就是異步的。

面試官:那能解釋下什麼是阻塞什麼是非阻塞麼?

程式員:如果必須等待A完成後才能執行B那麼這個就是阻塞的,如果A,B可以同時執行那麼就 是非阻塞的

面試官:那你的意思異步/同步的概念與阻塞非阻塞一樣了?

程式員:嗄。。。可以這麼說吧。我覺得可以

并發執行

的就是異步非阻塞的。one by one執行 的就是同步阻塞的

二:區分

每個人看去看同一個問題都會有不同的了解,原因就是因為每個人的看待問題的深度不一樣,就像上面的對白,程

序員的了解隻是停留在應用層面,代碼裡有多個IO操作,每個IO操作都可以不用互相等待的“同時”執行。

接下來我們就來探讨下異步/同步與阻塞/非阻塞它們其中的差別。

阻塞 / 非阻塞描述的是函數, 指通路某個函數時是否會阻塞線程(block),導緻線程進入阻塞狀态。

同步 / 異步描述的是執行IO操作的主體是誰,同步是由使用者态的程序自己去執行IO操作,異步是使用者态程序不關心IO細節,由核心态程序去完成IO操作然後通知使用者态程序。

好的,現在定義已經描述完了。現在可以區分它們之間的差別了麼?(吃瓜群衆:這TM的寫的是什麼?) ,别急,我們下面舉栗說明,包教包會。

三:舉栗

一般來說IO分為兩個階段,第一階段是等待資料階段,第二階段是核心空間的資料拷貝到使用者空間,假設一個線程(或是程序)P準備執行一個IO操作的話它會經曆以下過程:

第一階段:

P發出一個IO請求,這時候會有兩種情況:
1:立刻傳回: 非阻塞
2:一直等待,P調用sleep/wait休眠或是挂起,讓出CPU給别的線程/程序  阻塞
           

第二階段:

這時核心的資料終于準備好了,
那麼現在使用者程序想要讀取核心空間的資料有兩種方式:
1:  P自己把資料從核心空間拷貝到使用者空間       同步
2:P建立一個線程做資料copy的工作        異步
           

現在應該明白了吧。阻塞/非阻塞是針對IO的第一階段的描述。異步/同步是針對IO的第二階段的描述也就是IO的主體。

這裡主要比較難了解的就是同步/異步。首先P在發起IO的請求的時候如果P本身還要負責IO請求後的資料copy(核心空間到使用者空間)工作。那麼我們就可以說是同步的。

如果P在發起IO操作後資料copy的工作由核心線程/程序或是P自己再建立一個線程/程序去完成,那麼我們就可以稱之為異步

四:排列組合

同步阻塞IO:

  • 同一個線程在操作IO時一直阻塞,直到讀取資料成功,然後線程本身負責把資料從核心空間拷貝到使用者空間

同步非阻塞:

  • 同一個線程發起IO後,立即獲得傳回,後面定期輪詢資料讀取情況,發現資料讀取成功,線程本身負責把資料從核心空間拷貝到使用者空間

異步非阻塞:

  • 一個線程發起IO後,立即傳回,由另外的線程發現資料讀取成功,把資料從核心空間拷貝到使用者空間。

非阻塞同步IO由于讀寫方法非阻塞,并且需要使用者自己來進行讀寫,是以每次調用讀寫方法實際讀寫的位元組數是不确定的,是以需要一個Buffer來儲存每次讀寫的位元組狀态。更重要的是使用者不知道什麼時候完成了讀寫,一般需要用

while循環判斷Buffer的狀态來跟蹤讀寫。非阻塞異步IO由于是核心線程進行讀寫,并且在IO完成後會回調使用者提供的callback,程式設計模型就比較簡單,使用者隻需要調用讀寫,提供回調就可以了,比如 read(filename, callback)select / poll / epoll 從本質上說都是非阻塞同步IO,select會收到IO就緒的狀态,然後通知使用者去處理

IO,實際的IO操作還需要使用者等待核心複制操作。

要了解IO就緒和完成的差別。就緒指的是還需要使用者自己去處理,完成指的是核心幫助完成了,使用者不用關心IO過

程,隻需要提供回調函數。

五:并行/并發與異步

并行

  • 對多處理器而言--多個程式在同一時刻發生,具有并發的含義,但并發不一定并行,也亦是說并發事件之間不一定要同一時刻發生。
  • 并行:在單處理器中多道程式設計系統中,程序被交替執行,表現出一種并發的外部特種;在多處理器系統中,進

    程不僅可以交替執行,而且可以重疊執行。在多處理器上的程式才可實作并行處理。計算機作業系統中把并行性和并發性明顯區分開,主要是從微觀的角度來說的,具體是指程序的并行性(多處理機的情況下,多個程序同時運作)和并發性(單處理機的情況下,多個程序在同一時間間隔運作的)

并發

對單處理器而言--多個程式在同一時間段發生;

  • 并發中又有:互斥和同步:
    互斥:程序間互相排斥使用臨界資源;比如寫操作;
    
    同步:不是排斥關系而是依賴關系,前一個程序的輸出是後一個程序的輸入
    
    當第一個程序沒有結束時第二個程序必須等待,互相協同完成一些事情;
    
    具有同步關系的一組程序并發時發送的消息稱為消息或者事件;
    
               
  • 同步和異步:
    異步:就是線程B在等待A的結果的時候還可以繼續幹自己的事兒,
    
    之間通過消息和事件來通知對方,提高了程式運作的效率。
    
    簡而言之,就是不是站在那兒傻傻死等;異步和多線程并不是一回事,
    
    異步是最終目的,多線程隻是實作的一種方法。
               

轉自 轉自

exit(?)

繼續閱讀