Linux 同步非同步非阻塞阻塞的解析

2021-09-08 12:02:17 字數 3900 閱讀 9459

一、理解同步、非同步、阻塞、非阻塞

出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。

1 老張把水壺放到火上,立等水開。(同步阻塞)

老張覺得自己有點傻。

2 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。(同步非阻塞)

老張還是覺得自己有點傻,於是變高階了,買了把會響笛的那種水壺。水開之後,能大聲發出嘀~~~~的噪音。

3 老張把響水壺放到火上,立等水開。(非同步阻塞)

老張覺得這樣傻等意義不大。

4 老張把響水壺放到火上,去客廳看電視,水壺響之前不再去看它了,響了再去拿壺。(非同步非阻塞)

老張覺得自己聰明了。

所謂同步非同步,只是對於水壺而言。

普通水壺,同步;響水壺,非同步。

雖然都能幹活,但響水壺可以在自己完工之後,提示老張水開了。這是普通水壺所不能及的。

同步只能讓呼叫者去輪詢自己(情況2中),造成老張效率的低下。

所謂阻塞非阻塞,僅僅對於老張而言。

立等的老張,阻塞;看電視的老張,非阻塞。

情況1和情況3中老張就是阻塞的,媳婦喊他都不知道。雖然3中響水壺是非同步的,可對於立等的老張沒有太大的意義。所以一般非同步是配合非阻塞使用的,這樣才能發揮非同步的效用。

再找乙個買書的例子:

非同步/同步:

非同步: 你去書店,問《如何征服美少女》到貨沒,老闆說,沒到貨,到貨了給你打**。你就走了,而且不需要再沒接到老闆**之前再跑到書店問。

同步:你去書店,問《如何征服美少女》到貨沒,老闆說,沒到貨,你走了,過了一段時間,你又到書店,問《如何征服美少女》到貨沒,老闆說沒有,。。。。就這樣,你不斷的來書店自己詢問。直到你鞋都跑破了.....

注意:你離開書店(不管是非同步還是同步),是可以幹自己的事情的,比如去做個***。

阻塞/非阻塞

阻塞:你去書店,問《如何征服美少女》到貨沒有,老闆說,沒到貨,於是你就在書店苦等,等書到貨,除了幹坐著,啥也幹不了,直到書來。

非阻塞:你去書店,問《如何征服美少女》到貨沒,老闆說,沒到貨,你就走了。(至於還來不來書店,取決於你的心情吧。但是在計算機中,沒處理完的事情,是要處理的。)

非同步/同步 是你的到訊息的方式,關注的是訊息通訊機制 (synchronous communication/ asynchronous communication)

阻塞/非阻塞是你怎樣處理事情,關注的是程式在等待呼叫結果(訊息,返回值)時的狀態

兩組概念不是乙個層面上的。

在上面的例子中,你就相當於計算機中的 程序 ,你的兩條腿就相當於cpu。(比喻很牽強也)

二、解析

在高效能的i/o設計中,有兩個比較著名的模式reactor和proactor模式,其中reactor模式用於同步i/o,而proactor運用於非同步i/o操作。

在比較這兩個模式之前,我們首先的搞明白幾個概念,什麼是阻塞和非阻塞,什麼是同步和非同步。

同步和非同步是針對應用程式和核心的互動而言的,同步指的是使用者程序觸發io操作並等待或者輪詢的去檢視io操作是否就緒,而非同步是指使用者程序觸發io操作以後便開始做自己的事情,而當io操作已經完成的時候會得到io完成的通知(非同步的特點就是通知)。

而阻塞和非阻塞是針對於程序在訪問資料的時候,根據io操作的就緒狀態來採取的不同方式,說白了是一種讀取或者寫入操作函式的實現方式,阻塞方式下讀取或者寫入函式將一直等待,而非阻塞方式下,讀取或者寫入函式會立即返回乙個狀態值。

首先乙個io操作其實分成了兩個步驟:發起io請求和實際的io操作。

同步io和非同步io的區別就在於第二個步驟是否阻塞,如果實際的io讀寫阻塞請求程序,那麼就是同步io,因此阻塞io、非阻塞io、io服用、訊號驅動io都是同步io,如果不阻塞,而是作業系統幫你做完io操作再將結果返回給你,那麼就是非同步io。

阻塞io和非阻塞io的區別在於第一步,發起io請求是否會被阻塞,如果阻塞直到完成那麼就是傳統的阻塞io,如果不阻塞,那麼就是非阻塞io。

說到阻塞,首先得說說i/o等待。i/o等待是不可避免的,那麼既然有了等待,就會有阻塞,但是注意,我們說的阻塞是指當前發起i/o操作的程序被阻塞

同步阻塞i/o便是指,當程序呼叫某些涉及i/o操作的系統呼叫或庫函式時,比如accept()(注意accept也算在了i/o操作)、send()、recv()等,程序便暫停下來,等待i/o操作完成再繼續執行。這是一種簡單而有效的i/o模型,它可以和多程序結合起來有效的利用cpu資源,但是代價就是多程序的大量記憶體開銷。

同步阻塞 程序坐水,就不能燒粥

同步非阻塞  類似於用乙個程序坐水,燒粥. while(true)  好處就是乙個程序處理多個i/o請求. 劣勢就是需要不停的輪詢.

區別在於等不等待資料就緒. 因為資料佔了等待的80%時間. 同步非阻塞的優勢就是乙個程序裡同時處理多個i/o操作。

在同步阻塞i/o中,程序實際上等待的時間可能包括兩部分,乙個是等待資料的就緒,另乙個是等待資料的複製,對於網路i/o來說,前者的時間可能要更長一些。與此不同的是,同步非阻塞i/o的呼叫不會等待資料的就緒,如果資料不可讀或者不可寫,它會立即返回告訴程序。

比如我們使用非阻塞recv()接收網路資料的時候,如果網絡卡緩衝區中沒有可接收的資料,函式就及時返回,告訴程序沒有資料可讀了。相比於阻塞i/o,這種非阻塞i/o結合反覆的輪詢來嘗試

資料是否就緒,防止程序被阻塞,最大的好處便在於可以在乙個程序裡同時處理多個i/o操作。但正是由於需要程序執行多次的輪詢來檢視資料是否就緒,這花費了大量的cpu時間,使得程序處於忙碌等待狀態。

非阻塞i/o一般只針對網路i/o有效,我們只要在socket的選項設定中使用o_nonblock即可,這樣對於該socket的send()或recv()便採用非阻塞方式。

如果伺服器想要同時接收多個tcp連線的資料,就必須輪流對每個socket呼叫接收資料的方法,比如recv()。不管這些socket有沒有可以接收的資料,都要詢問一遍,假如大部分socket並沒有資料可以接收,那麼程序便會浪費很多cpu時間用於檢查這些socket,這顯然不是我們所希望看到的。

同步和非同步,阻塞和非阻塞,有些混用,其實它們完全不是一回事,而且它們修飾的物件也不相同。

阻塞和非阻塞是指當程序訪問的資料如果尚未就緒,程序是否需要等待,簡單說這相當於函式內部的實現區別,也就是未就緒時是直接返回還是等待就緒;

而同步和非同步是指訪問資料的機制,同步一般指主動請求並等待i/o操作完畢的方式,當資料就緒後在讀寫的時候必須阻塞(區別就緒與讀寫二個階段,同步的讀寫必須阻塞),非同步則指主動請求資料後便可以繼續處理其它任務,隨後等待i/o,操作完畢的通知,這可以使程序在資料讀寫時也不阻塞。(等待"通知")

多數情況下,web伺服器對這些請求採用基於佇列的自由競爭,通過多執行流(多程序或多執行緒)來充分佔 用cpu以及i/o資源,減少任何無辜的等待時間,這其中包括了很多種具體實現的併發策略,在實際應用中,特別是web伺服器,同時處理大量的檔案描述符是必不可少的.多路i/o就緒通知的出現,提供了對大量檔案描述符就緒檢查的高效能方案,它允許程序(比如電子屏,會聞到各個飯館做好飯菜的味道)通過一種方法來同時監視所有檔案描述符,並可以快速獲得所有就緒的檔案描述符,然後只針對這些檔案描述符進行資料訪問。

回到買麵條的故事中,假如你不止買了乙份麵條,還在其它幾個小吃店買了餃子、粥、餡餅等,因為一起逛街的朋友看到你的麵條後也餓了。這些東西都需要時間來等待製作。在同步非阻塞i/o模型中,你要輪流不停的去各個小吃店詢問進度,痛苦不堪。現在引入多路i/o就緒通知後,小吃城管理處給大廳安裝了一塊電子螢幕,以後所有小吃店的食物做好後,都會顯示在螢幕上,這可真是個好訊息,你只需要間隔性的看看大螢幕就可以了,也許你還可以同時逛逛附近的商店,在不遠處也可以看到大螢幕。

多路就緒:1.強調多路. 2.只針對請求資料是否就緒.不針對i/o讀寫

epoll針對的是這樣的場景.

select, epoll都只需要程序(我)被動接收到資料就緒(麵條)"通知".符合非同步的定義. 不需要一直在飯館等(同步阻塞).或輪詢(同步非阻塞).

阻塞,非阻塞,非同步,同步

之前一直對這個概念理不太清楚,今天看到一篇文章感覺不錯 本文 老張愛喝茶,廢話不說,煮開水。出場人物 老張,水壺兩把 普通 水壺,簡稱水壺 會響的水壺,簡稱響水壺 1 老張把水壺放到火上,立等水開。同步阻塞 老張覺得自己有點傻 2 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。同步非阻...

同步 非同步 阻塞 非阻塞

故事 老王燒開水。出場人物 老張,水壺兩把 普通水壺,簡稱水壺 會響的水壺,簡稱響水壺 老王想了想,有好幾種等待方式 1.老王用水壺煮水,並且站在那裡,不管水開沒開,每隔一定時間看看水開了沒。同步阻塞 老王想了想,這種方法不夠聰明。2.老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網,但是...

同步 非同步 阻塞 非阻塞

故事 老王燒開水。出場人物 老張,水壺兩把 普通水壺,簡稱水壺 會響的水壺,簡稱響水壺 老王想了想,有好幾種等待方式 1.老王用水壺煮水,並且站在那裡,不管水開沒開,每隔一定時間看看水開了沒。同步阻塞 老王想了想,這種方法不夠聰明。2.老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網,但是...