回答一
轉(zhuǎn)載自:銀月游俠
這幾個概念涂乌,上面不少答案已經(jīng)寫得很清楚了艺栈。這里我結(jié)合自己的理解,簡單地聊一下為什么這幾個概念容易混淆湾盒。如果有錯誤之處湿右,懇請批評指正。我認(rèn)為同步罚勾、異步毅人、阻塞、非阻塞尖殃,是分3個層次的:CPU層次丈莺;線程層次;程序員感知層次分衫。
這幾個概念之所以容易混淆场刑,是因為沒有分清楚是在哪個層次進(jìn)行討論。
CPU層次
在CPU層次蚪战,或者說操作系統(tǒng)進(jìn)行IO和任務(wù)調(diào)度的層次牵现,現(xiàn)代操作系統(tǒng)通常使用異步非阻塞方式進(jìn)行IO(有少部分IO可能會使用同步非阻塞輪詢),即發(fā)出IO請求之后邀桑,并不等待IO操作完成瞎疼,而是繼續(xù)執(zhí)行下面的指令(非阻塞),IO操作和CPU指令互不干擾(異步)壁畸,最后通過中斷的方式來通知IO操作完成結(jié)果贼急。
線程層次
在線程層次茅茂,或者說操作系統(tǒng)調(diào)度單元的層次,操作系統(tǒng)為了減輕程序員的思考負(fù)擔(dān)太抓,將底層的異步非阻塞的IO方式進(jìn)行封裝空闲,把相關(guān)系統(tǒng)調(diào)用(如read,write等)以同步的方式展現(xiàn)出來走敌。然而碴倾,同步阻塞的IO會使線程掛起,同步非阻塞的IO會消耗CPU資源在輪詢上掉丽。為了解決這一問題跌榔,就有3種思路:多線程(同步阻塞);
IO多路復(fù)用(select捶障,poll僧须,epoll)(同步非阻塞,嚴(yán)格地來講项炼,是把阻塞點改變了位置)担平;
直接暴露出異步的IO接口,如kernel-aio和IOCP(異步非阻塞)芥挣。
程序員感知層次
在Linux中驱闷,上面提到的第2種思路用得比較廣泛,也是比較理想的解決方案空免。然而空另,直接使用select之類的接口,依然比較復(fù)雜蹋砚,所以各種庫和框架百花齊放扼菠,都試圖對IO多路復(fù)用進(jìn)行封裝。此時坝咐,庫和框架提供的API又可以選擇是以同步的方式還是異步的方式來展現(xiàn)循榆。如python的asyncio庫中,就通過協(xié)程墨坚,提供了同步阻塞式的API秧饮;如node.js中,就通過回調(diào)函數(shù)泽篮,提供了異步非阻塞式的API盗尸。總結(jié)因此,我們在討論同步帽撑、異步泼各、阻塞、非阻塞時亏拉,必須先明確是在哪個層次進(jìn)行討論扣蜻。比如node.js逆巍,我們可以說她在程序員感知層次提供了異步非阻塞的API,也可以說在Linux下莽使,她在線程層次以同步非阻塞的epoll來實現(xiàn)锐极。
回答二
轉(zhuǎn)載自:愚抄
老張愛喝茶,廢話不說吮旅,煮開水溪烤。
出場人物:老張,水壺兩把(普通水壺庇勃,簡稱水壺;會響的水壺槽驶,簡稱響水壺)责嚷。
1 老張把水壺放到火上,立等水開掂铐。(同步阻塞)
老張覺得自己有點傻
2 老張把水壺放到火上罕拂,去客廳看電視,時不時去廚房看看水開沒有全陨。(同步非阻塞)
老張還是覺得自己有點傻爆班,于是變高端了,買了把會響笛的那種水壺辱姨。水開之后柿菩,能大聲發(fā)出嘀~~~~的噪音。
3 老張把響水壺放到火上雨涛,立等水開枢舶。(異步阻塞)
老張覺得這樣傻等意義不大
4 老張把響水壺放到火上,去客廳看電視替久,水壺響之前不再去看它了凉泄,響了再去拿壺。(異步非阻塞)
老張覺得自己聰明了蚯根。
所謂同步異步后众,只是對于水壺而言。
普通水壺颅拦,同步蒂誉;響水壺,異步矩距。
雖然都能干活拗盒,但響水壺可以在自己完工之后,提示老張水開了锥债。這是普通水壺所不能及的陡蝇。
同步只能讓調(diào)用者去輪詢自己(情況2中)痊臭,造成老張效率的低下。
所謂阻塞非阻塞登夫,僅僅對于老張而言广匙。
立等的老張,阻塞恼策;看電視的老張鸦致,非阻塞。
情況1和情況3中老張就是阻塞的涣楷,媳婦喊他都不知道分唾。雖然3中響水壺是異步的,可對于立等的老張沒有太大的意義狮斗。所以一般異步是配合非阻塞使用的绽乔,這樣才能發(fā)揮異步的效用。
回答三
轉(zhuǎn)載自:大姚
網(wǎng)絡(luò)編程釋疑之:同步碳褒,異步折砸,阻塞,非阻塞
一講到網(wǎng)絡(luò)編程的I/O模型沙峻,總會涉及到這幾個概念睦授。問了很多人,沒幾個能清晰地講出他們之間的區(qū)別聯(lián)系摔寨,甚至在網(wǎng)絡(luò)上也有很多不同的觀點去枷,也不知是中國文字釋義的博大精深,還是本來這幾個概念就是繞人不倦祷肯。今天我也來給大家講解一下我對這幾個概念的理解沉填。
既然網(wǎng)絡(luò)上眾說紛紜,不如找個權(quán)威參考一下佑笋,這個權(quán)威就是《UNIX網(wǎng)絡(luò)編程:卷一》**第六章——I/O復(fù)用翼闹。書中向我們提及了5種類UNIX下可用的I/O模型:
- 阻塞式I/O;
- 非阻塞式I/O蒋纬;
- I/O復(fù)用(select猎荠,poll,epoll...)蜀备;
- 信號驅(qū)動式I/O(SIGIO)关摇;
- 異步I/O(POSIX的aio_系列函數(shù));
阻塞式I/O模型:默認(rèn)情況下碾阁,所有套接字都是阻塞的输虱。怎么理解?先理解這么個流程脂凶,一個輸入操作通常包括兩個不同階段:
(1)等待數(shù)據(jù)準(zhǔn)備好宪睹;(2)從內(nèi)核向進(jìn)程復(fù)制數(shù)據(jù)愁茁。
對于一個套接字上的輸入操作,第一步通常涉及等待數(shù)據(jù)從網(wǎng)絡(luò)中到達(dá)亭病。當(dāng)所有等待分組到達(dá)時鹅很,它被復(fù)制到內(nèi)核中的某個緩沖區(qū)。第二步就是把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用程序緩沖區(qū)罪帖。 好促煮,下面我們以阻塞套接字的recvfrom的的調(diào)用圖來說明阻塞
標(biāo)紅的這部分過程就是阻塞,直到阻塞結(jié)束recvfrom才能返回整袁。
非阻塞式I/O: 以下這句話很重要:進(jìn)程把一個套接字設(shè)置成非阻塞是在通知內(nèi)核菠齿,當(dāng)所請求的I/O操作非得把本進(jìn)程投入睡眠才能完成時,不要把進(jìn)程投入睡眠葬项,而是返回一個錯誤泞当。看看非阻塞的套接字的recvfrom操作如何進(jìn)行
可以看出recvfrom總是立即返回民珍。
I/O多路復(fù)用:雖然I/O多路復(fù)用的函數(shù)也是阻塞的,但是其與以上兩種還是有不同的盗飒,I/O多路復(fù)用是阻塞在select嚷量,epoll這樣的系統(tǒng)調(diào)用之上,而沒有阻塞在真正的I/O系統(tǒng)調(diào)用如recvfrom之上逆趣。如圖
信號驅(qū)動式I/O:用的很少蝶溶,就不做講解了。直接上圖
等等田轧,大家一定要問了,同步這個概念你怎么沒涉及鞍盎帧傻粘?別急,您先看總結(jié)帮掉。 其實前四種I/O模型都是同步I/O操作弦悉,他們的區(qū)別在于第一階段,而他們的第二階段是一樣的:在數(shù)據(jù)從內(nèi)核復(fù)制到應(yīng)用緩沖區(qū)期間(用戶空間)蟆炊,進(jìn)程阻塞于recvfrom調(diào)用稽莉。相反,異步I/O模型在這兩個階段都要處理涩搓。
同步I/O操作:導(dǎo)致請求進(jìn)程阻塞污秆,直到I/O操作完成劈猪;
異步I/O操作:不導(dǎo)致請求進(jìn)程阻塞。
好混狠,下面我用我的語言來總結(jié)一下阻塞岸霹,非阻塞,同步将饺,異步
阻塞贡避,非阻塞:進(jìn)程/線程要訪問的數(shù)據(jù)是否就緒,進(jìn)程/線程是否需要等待予弧;
同步刮吧,異步:訪問數(shù)據(jù)的方式,同步需要主動讀寫數(shù)據(jù)掖蛤,在讀寫數(shù)據(jù)的過程中還是會阻塞杀捻;異步只需要I/O操作完成的通知,并不主動讀寫數(shù)據(jù)蚓庭,由操作系統(tǒng)內(nèi)核完成數(shù)據(jù)的讀寫致讥。
一些想法
我覺得這個回答勝在對于同步,異步器赞,阻塞垢袱,非阻塞的框架的搭建非常好,當(dāng)然還有一些在各個層次的細(xì)節(jié)港柜,可以參見其他回答请契,也是非常優(yōu)秀的,比如說這個網(wǎng)絡(luò)編程釋疑之:同步夏醉,異步爽锥,阻塞,非阻塞畔柔。
還有其他優(yōu)質(zhì)的回答見:怎樣理解阻塞非阻塞與同步異步的區(qū)別氯夷?