同步異步阻礙非阻礙

做者:嚴肅
連接:https://www.zhihu.com/question/19732473/answer/20851256
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
 
「阻塞」與"非阻塞"與"同步"與「異步"不能簡單的從字面理解,提供一個從分佈式系統角度的回答。
1.同步與異步
同步和異步關注的是消息通訊機制 (synchronous communication/ asynchronous communication)
所謂同步,就是在發出一個*調用*時,在沒有獲得結果以前,該*調用*就不返回。可是一旦調用返回,就獲得返回值了。
換句話說,就是由*調用者*主動等待這個*調用*的結果。
而異步則是相反,*調用*在發出以後,這個調用就直接返回了,因此沒有返回結果。換句話說,當一個異步過程調用發出後,調用者不會馬上獲得結果。而是在*調用*發出後,*被調用者*經過狀態、通知來通知調用者,或經過回調函數處理這個調用。
典型的異步編程模型好比Node.js
舉個通俗的例子:
你打電話問書店老闆有沒有《分佈式系統》這本書,若是是同步通訊機制,書店老闆會說,你稍等,」我查一下",而後開始查啊查,等查好了(多是5秒,也多是一天)告訴你結果(返回結果)。
而異步通訊機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,而後直接掛電話了(不返回結果)。而後查好了,他會主動打電話給你。在這裏老闆經過「回電」這種方式來回調。
2. 阻塞與非阻塞
阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態.
阻塞調用是指調用結果返回以前,當前線程會被掛起。調用線程只有在獲得結果以後纔會返回。
非阻塞調用指在不能馬上獲得結果以前,該調用不會阻塞當前線程。
仍是上面的例子,
你打電話問書店老闆有沒有《分佈式系統》這本書,你若是是阻塞式調用,你會一直把本身「掛起」,直到獲得這本書有沒有的結果,若是是非阻塞式調用,你無論老闆有沒有告訴你,你本身先一邊去玩了, 固然你也要偶爾過幾分鐘check一下老闆有沒有返回結果。
在這裏阻塞與非阻塞與是否同步異步無關。跟老闆經過什麼方式回答你結果無關。
 
老張愛喝茶,廢話不說,煮開水。
出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。
1 老張把水壺放到火上,立等水開。(同步阻塞)
老張以爲本身有點傻
2 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。(同步非阻塞)
老張仍是以爲本身有點傻,因而變高端了,買了把會響笛的那種水壺。水開以後,能大聲發出嘀~~~~的噪音。
3 老張把響水壺放到火上,立等水開。(異步阻塞)
老張以爲這樣傻等意義不大
4 老張把響水壺放到火上,去客廳看電視,水壺響以前再也不去看它了,響了再去拿壺。(異步非阻塞)
老張以爲本身聰明瞭。
 
所謂同步異步,只是對於水壺而言。
普通水壺,同步;響水壺,異步。
雖然都能幹活,但響水壺能夠在本身完工以後,提示老張水開了。這是普通水壺所不能及的。
同步只能讓調用者去輪詢本身(狀況2中),形成老張效率的低下。
所謂阻塞非阻塞,僅僅對於老張而言。
立等的老張,阻塞;看電視的老張,非阻塞。
狀況1和狀況3中老張就是阻塞的,媳婦喊他都不知道。雖然3中響水壺是異步的,可對於立等的老張沒有太大的意義。因此通常異步是配合非阻塞使用的,這樣才能發揮異步的效用。
 
 
做者:愚抄
連接:https://www.zhihu.com/question/19732473/answer/23434554
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
 
做者:廠長
連接:https://www.zhihu.com/question/33578075/answer/56951771
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
 
 
 
譯文以下:
若是你去年注意過技術方面的新聞,我敢說你至少看到node.js不下一兩次。那麼問題來了「node.js是什麼?」。有些人沒準會告訴你「這是一種經過JavaScript語言開發web服務端的東西」。若是這種晦澀解釋還沒把你搞暈,你沒準會接着問:「爲何咱們要用node.js?」,別人通常會告訴你:node.js有非阻塞,事件驅動I/O等特性,從而讓高併發(high concurrency)在的輪詢(Polling)和comet構建的應用中成爲可能。
 
當你看完這些解釋以爲跟看天書同樣的時候,你估計也懶得繼續問了。不過沒事。我這篇文章就是在避開高端術語的同時,幫助你你理解node.js的。
 
瀏覽器給網站發請求的過程一直沒怎麼變過。當瀏覽器給網站發了請求。服務器收到了請求,而後開始搜尋被請求的資源。若是有須要,服務器還會查詢一下數據庫,最後把響應結果傳回瀏覽器。不過,在傳統的web服務器中(好比Apache),每個請求都會讓服務器建立一個新的進程來處理這個請求。
 
後來有了Ajax。有了Ajax,咱們就不用每次都請求一個完整的新頁面了,取而代之的是,每次只請求須要的部分頁面信息就能夠了。這顯然是一個進步。可是好比你要建一個FriendFeed這樣的社交網站(相似人人網那樣的刷朋友新鮮事的網站),你的好友會隨時的推送新的狀態,而後你的新鮮事會實時自動刷新。要達成這個需求,咱們須要讓用戶一直與服務器保持一個有效鏈接。目前最簡單的實現方法,就是讓用戶和服務器之間保持長輪詢(long polling)。
 
HTTP請求不是持續的鏈接,你請求一次,服務器響應一次,而後就完了。長輪訓是一種利用HTTP模擬持續鏈接的技巧。具體來講,只要頁面載入了,無論你需不須要服務器給你響應信息,你都會給服務器發一個Ajax請求。這個請求不一樣於通常的Ajax請求,服務器不會直接給你返回信息,而是它要等着,直到服務器以爲該給你發信息了,它纔會響應。好比,你的好友發了一條新鮮事,服務器就會把這個新鮮事當作響應發給你的瀏覽器,而後你的瀏覽器就刷新頁面了。瀏覽器收到響應刷新完以後,再發送一條新的請求給服務器,這個請求依然不會當即被響應。因而就開始重複以上步驟。利用這個方法,可讓瀏覽器始終保持等待響應的狀態。雖然以上過程依然只有非持續的Http參與,可是咱們模擬出了一個看似持續的鏈接狀態
 
咱們再看傳統的服務器(好比Apache)。每次一個新用戶連到你的網站上,你的服務器就得開一個鏈接。每一個鏈接都須要佔一個進程,這些進程大部分時間都是閒着的(好比等着你好友發新鮮事,等好友發完纔給用戶響應信息。或者等着數據庫返回查詢結果什麼的)。雖然這些進程閒着,可是照樣佔用內存。這意味着,若是用戶鏈接數的增加到必定規模,你服務器沒準就要耗光內存直接癱了。
 
這種狀況怎麼解決?解決方法就是剛纔上邊說的:非阻塞事件驅動。這些概念在咱們談的這個情景裏面其實沒那麼難理解。你把非阻塞的服務器想象成一個loop循環,這個loop會一直跑下去。一個新請求來了,這個loop就接了這個請求,把這個請求傳給其餘的進程(好比傳給一個搞數據庫查詢的進程),而後響應一個回調(callback)。完事了這loop就接着跑,接其餘的請求。這樣下來。服務器就不會像以前那樣傻等着數據庫返回結果了。
 
若是數據庫把結果返回來了,loop就把結果傳回用戶的瀏覽器,接着繼續跑。在這種方式下,你的服務器的進程就不會閒着等着。從而在理論上說,同一時刻的數據庫查詢數量,以及用戶的請求數量就沒有限制了。服務器只在用戶那邊有事件發生的時候才響應,這就是事件驅動。
 
FriendFeed是用基於Python的非阻塞框架Tornado (知乎也用了這個框架) 來實現上面說的新鮮事功能的。不過,Node.js就比前者更妙了。Node.js的應用是經過javascript開發的,而後直接在Google的變態V8引擎上跑。用了Node.js,你就不用擔憂用戶端的請求會在服務器裏跑了一段可以形成阻塞的代碼了。由於javascript自己就是事件驅動的腳本語言。你回想一下,在給前端寫javascript的時候,更多時候你都是在搞事件處理和回調函數。javascript自己就是給事件處理量身定製的語言。
 
Node.js仍是處於初期階段。若是你想開發一個基於Node.js的應用,你應該會須要寫一些很底層代碼。可是下一代瀏覽器很快就要採用WebSocket技術了,從而長輪詢也會消失。在Web開發裏,Node.js這種類型的技術只會變得愈來愈重要。
 
以上
相關文章
相關標籤/搜索