背景
很多人在同步異步、阻塞非阻塞這2組概念上不能講的很清楚,而且網絡上也有幾種完全不同的看法,總之這個部分有不少爭議。
筆者也在這部分困惑過,花了一些時間去弄透這個問題,以下是個人理解的一些總結。希望能幫到大家。
1. 通用概念
例子:”我”燒水(注意:這裏的主語是”我”,也就是我們討論的who)
1.1. 同步異步
1.1.1. 例子
關注點:是否需要”我主動”去看水燒開沒(注意,”我”和”主動”這兩個詞)
- 同步:“我”要主動看水燒開沒
- 異步:不需要”我”主動去看水燒開,水壺響了通知”我”
1.1.2. 概念
抽象概念:事情執行者對事情結果的獲取機制(who:事情執行者)
- 同步:事情執行者主動獲取事情結果
- 異步:事情執行者被動獲取事情結果
1.2. 阻塞非阻塞
1.2.1. 例子
關注點:水燒開前,”我”能不能去做其他事情
- 阻塞:
- 水沒燒開,我一直等着(全程阻塞)
- 我去幹其他事情了,但是隔一會兒來看一次水燒開沒(來看的時候阻塞)
- 非阻塞:
水沒燒開,”我”去拖地了,拖完地又看了會兒電視
1.2.2. 概念
抽象概念:事情執行者得到事情結果前能不能去做其他事情(who:事情執行者)
- 阻塞:事情執行者得到結果前不能去做其他事情
- 非阻塞:事情執行者得到結果前可以去做其他事情
1.3. 總結
- 同步一定是會發生阻塞的,只是阻塞的時間長短問題。
- 我主動看水燒開(同步),水燒開前我一直等着(阻塞):全程阻塞
- 我主動看水燒開(同步),隔一會兒來看水燒開(看的過程是阻塞):局部阻塞
- 異步一定是非阻塞的:
- 不需要我主動去看水燒開(異步),燒水過程中我可以去做任何事情(非阻塞)。
2. 網絡編程層面
網絡編程層面主要涉及的就是IO,所以,這裏主要講IO。這塊兒其實在《UNIX網絡編程卷1 第6章 IO複用》中講的非常清楚了,建議大家看一下,我引用其中的一些關鍵點。具體的可以找書去看。
2.1. POSIX定義
- 同步I/O操作:導致請求進程阻塞,直到I/O操作完成;
- 異步I/O操作:不導致請求進程阻塞。
2.2. IO模型
根據POXIX的定義,下面圖中的五種IO模型,其實前四種都是同步IO。
2.3. 總結
注意:這裏的who是進程
2.3.1. 同步IO
- 進程主動查看關心的IO事件是否就緒,就緒時再執行相關操作
- 注意:進程的阻塞發生在select/epoll/poll等待事件時
- 進程主動執行讀寫
- 注意:進程的阻塞發生在數據未到達(設備未收到數據),或者未就緒(內核空間和用戶空間的數據copy未完成)
2.3.2. 異步IO
異步IO是需要底層操作系統內核做支持的,比如linux的AIO, windows的IOCP。
- 進程不用主動去查看關心的IO事件,只需要把關心的IO事件、數據buffer以及要綁定的回調函數或者signal直接告訴內核,內核發現IO時間就緒時,直接調用回調函數或者發送綁定的signal
- 注意:IO事件相關的數據,由內核直接將數據copy到用戶空間(異步讀),或者從用戶空間copy至內核空間(異步寫)
- 進程被動執行數據操作
- 注意:進程收到內核通知後,在1中綁定的數據buffer裏就已經有數據了,進程直接對數據進行相關處理即可。