目的##
為后期學(xué)習(xí) Netty框架打好理論基礎(chǔ)舶沿,并且在分布式RPC 服務(wù)中對客戶端與服務(wù)端之間服務(wù)的調(diào)用,底層數(shù)據(jù)通訊可以使用Netty 進(jìn)行封裝配并。
記錄結(jié)構(gòu)##
- Java NIO(一)--I/O模型: 阻塞括荡、非阻塞吸祟、I/O復(fù)用敢靡、同步、異步
地址:http://www.reibang.com/writer#/notebooks/5970279/notes/7531041/preview - Java NIO(二)--Channel劳跃、Buffer观腊、Selector
地址:待定 - Java NIO(三)--多路復(fù)用之TCP傳輸中的NIO應(yīng)用
地址:待定 - 福利彩蛋
今天記錄I/O模型中的阻塞邑闲、非阻塞、I/O復(fù)用梧油、同步苫耸、異步。
混沌的概念##
對于上述四種概念婶溯,常常使我陷入混沌,我經(jīng)常這樣想同步不就是阻塞的么?異步不就是非阻塞的么迄委?
我也會去看下別人寫的博客以驗(yàn)證我的想法是正確的褐筛,事實(shí)上,大多博客也這樣舉例子:同步類似于你叫某人吃飯叙身,某人不應(yīng)答你渔扎,你就一直等著他,這期間你什么事情都不能做信轿,也就是說你在等待某人去吃飯這個時刻內(nèi)一直都是阻塞的晃痴。
針對于上述的舉例,我一直深信不疑财忽,一句話倘核,沒毛病。
但直到我看到UNIX 網(wǎng)絡(luò)編程之后即彪,才發(fā)現(xiàn)理解有偏差紧唱,起碼我之前的理解是將I/O操作中的概念結(jié)合起來記憶。即:同步==阻塞 異步==非阻塞隶校。
但其實(shí)漏益,以上的記憶有點(diǎn)以偏概全,或者說根本沒有清晰的認(rèn)識深胳。
話不多說绰疤,開始記錄。
1. 明確I/O考察的對象和流程##
1.1 參考Unix網(wǎng)絡(luò)編程舞终,一個輸入操作通常包括兩個不同的階段:
- 等待數(shù)據(jù)準(zhǔn)備好轻庆;
- 從內(nèi)核向進(jìn)程復(fù)制數(shù)據(jù)。
1.2 對于一個套接字的輸入操作:
- 通常涉及等待數(shù)據(jù)從網(wǎng)絡(luò)到達(dá)权埠,當(dāng)所等待分組到達(dá)時榨了,被復(fù)制到內(nèi)核的某個緩沖區(qū);
- 把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用進(jìn)程緩沖區(qū)。
注意: 理解上述兩個不同階段對于后續(xù)理解I/O模型尤其是非阻塞I/O與同步I/O關(guān)系十分必要攘蔽。
2. I/O模型##
2.1 阻塞式I/O模型
阻塞式I/O是最流行的I/O龙屉,也是所有套接字默認(rèn)的I/O。Java BIO中對socket 網(wǎng)絡(luò)數(shù)據(jù)通信的
封裝 就采用的是這種方式满俗。當(dāng)然效率也是低下的转捕。
阻塞式I/O是最流行的I/O,也是所有套接字默認(rèn)的I/O唆垃。
(注:所有圖片來源 Unix網(wǎng)絡(luò)編程卷1五芝,第三版)
如圖所示,進(jìn)程調(diào)用recvfrom系統(tǒng)調(diào)用辕万,直到網(wǎng)絡(luò)數(shù)據(jù)報到達(dá)且被復(fù)制到應(yīng)用進(jìn)程緩沖區(qū)中或發(fā)生錯誤才返回枢步。
注意:也就是說沉删,進(jìn)程從調(diào)用recvfrom開始到返回的整個時段都是阻塞的(上述1.1兩個階段都是阻塞),recvfrom成功返回后醉途,應(yīng)用進(jìn)程才開始處理數(shù)據(jù)報矾瑰。
上述的注意讀三遍
2.2 非阻塞I/O模型
直接上圖:
如圖所示,不同于阻塞式I/O隘擎,非阻塞I/O在第一階段數(shù)據(jù)沒有準(zhǔn)備好的時候殴穴,不阻塞,而是直接返回一個錯誤(EWOULDBLOCK)货葬。
所以一般采用輪詢(polling)的方式采幌,應(yīng)用進(jìn)程持續(xù)輪詢內(nèi)核,查看數(shù)據(jù)是否準(zhǔn)備好震桶。當(dāng)數(shù)據(jù)準(zhǔn)備好時休傍,被復(fù)制到應(yīng)用進(jìn)程緩沖區(qū)(第二階段)。
注意:值得注意的一點(diǎn)是尼夺,當(dāng)?shù)谝浑A段數(shù)據(jù)準(zhǔn)備完成后尊残,進(jìn)入第二階段,內(nèi)核向內(nèi)存的復(fù)制淤堵。這一階段仍然是阻塞的寝衫,這對于后續(xù)理解非阻塞與同步的關(guān)系十分重要。
上述注意項(xiàng)讀三遍拐邪。
2.3 I/O多路復(fù)用模型
I/O復(fù)用最常見的就是select和epoll慰毅,其阻塞發(fā)生在上述兩個系統(tǒng)調(diào)用之一,而不是真正的I/O系統(tǒng)調(diào)用上扎阶。 Java NIO 對TCP 網(wǎng)絡(luò)通信的封裝內(nèi)部采用的就是這種原理汹胃。
當(dāng)用戶進(jìn)程調(diào)用了select,那么整個進(jìn)程會被阻塞與select东臀。內(nèi)核會“監(jiān)視”所有select負(fù)責(zé)的套接字着饥,當(dāng)任何一個套接字中的數(shù)據(jù)準(zhǔn)備好了,select就會返回惰赋。(進(jìn)程阻塞)
這時候進(jìn)入第二階段宰掉,完成內(nèi)核向內(nèi)存的數(shù)據(jù)復(fù)制。(進(jìn)程阻塞)
注意:I/O復(fù)用的優(yōu)勢在于同時等待多個描述符就緒赁濒,單就一個描述符可言轨奄,其沒有優(yōu)勢,反而還會因?yàn)槎嘁淮蝧elect系統(tǒng)調(diào)用存在劣勢拒炎。
上述注意項(xiàng)讀三遍挪拟。
2.4 異步I/O模型
異步I/O的工作機(jī)制是告知內(nèi)核啟動某個操作,并讓內(nèi)核在整個操作(包括第二階段數(shù)據(jù)從內(nèi)核向內(nèi)存的復(fù)制)完成后告知我們击你。
如下圖所示:
注意:異步I/O要通過調(diào)用特殊API實(shí)現(xiàn)(如POSIX的aio_read)玉组,可以看出谎柄,其在兩個階段都是沒有對于用戶進(jìn)程的阻塞的,依靠信號通知進(jìn)程整個過程完成惯雳。
上述注意讀三遍
2.5 同步谷誓、異步與阻塞、非阻塞吨凑、I/O復(fù)用的關(guān)系
在了解了阻塞式I/O、非阻塞式I/O户辱、I/O多路復(fù)用鸵钝、異步I/O后我們看下這幾個模式的I/O模型與同步異步模型有什么關(guān)系。
注意:重頭戲庐镐,接下來就是徹底領(lǐng)悟這幾個概念之間關(guān)系恩商,讓你不再混沌,請保持接受狀態(tài)必逆,保持信心看下去怠堪。
首先先來再明確一下同步、異步I/O之間的區(qū)別名眉。
書中所述粟矿,POSIX把兩種術(shù)語定義如下:
同步I/O:導(dǎo)致請求進(jìn)程阻塞,直到I/O操作完成损拢;(兩個階段(等待網(wǎng)絡(luò)數(shù)據(jù)到達(dá)內(nèi)核空間緩存區(qū)域陌粹,以及將內(nèi)核空間緩存區(qū)域中的數(shù)據(jù)復(fù)制到用戶進(jìn)程緩存中)中只要有一個階段阻塞,那整個I/O操作就就是同步)
異步I/O:不導(dǎo)致請求進(jìn)程阻塞福压。 (兩個階段都不阻塞掏秩,那么就是異步I/O)
注意:所以說,阻塞式I/O荆姆, 非阻塞I/O蒙幻, I/O復(fù)用由于都導(dǎo)致了請求進(jìn)程阻塞,所以均屬于同步I/O胆筒。
(值得注意的是非阻塞I/O邮破,正如之前提示要注意的,其在第二階段內(nèi)核向內(nèi)存復(fù)制數(shù)據(jù)是會導(dǎo)致用戶進(jìn)程的阻塞腐泻,所以也屬于同步I/O
上述注意讀三遍
3. 總結(jié)
如下圖所示:(暫時忽略信號驅(qū)動I/O)
可以看出阻塞式决乎、非阻塞式、與I/O復(fù)用派桩,其不同之處在于第一階段构诚,第二階段的處理方式相同(均阻塞與recvfrom調(diào)用),這也是剛才說到的將他們歸于同步I/O的原因铆惑。
注意:異步I/O不存在請求進(jìn)程阻塞的情況范嘱。同時注意前三種I/O模型在第一階段的處理方式(阻塞送膳,返回+輪詢,阻塞于select等)丑蛤,區(qū)分這三種I/O模型叠聋。
上述注意讀三遍
關(guān)于公眾號
精進(jìn)!
道友們受裹,你們好碌补。早前個人就有開設(shè)公眾號的念想,今年10月終于開搞了棉饶。
我的個人的 訂閱號--T客來了厦章;
平時自己會總結(jié)一些后端開發(fā)相關(guān)的技術(shù);
最近也迷上了音視頻開發(fā)相關(guān)技術(shù)照藻;
技術(shù)分享包括:
- 1.FFmpeg 工程實(shí)戰(zhàn)袜啃、
- 2.數(shù)據(jù)庫 MySQL原理與實(shí)戰(zhàn)、
- 3.Redis中間件幸缕、
- 4.Nginx群发、Java并發(fā)編程、
-
5.Go語言方面的技術(shù)知識與實(shí)操;
T客來了
點(diǎn)擊微信圖標(biāo)发乔,掃碼就可以添加哦~
完熟妓。