【多线程】0.理解一下5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO
5種IO模型、阻塞IO和非阻塞IO、同步IO和異步IO
看了一些文章,發(fā)現(xiàn)有很多不同的理解,可能是因?yàn)榇蠹胰肭械慕嵌取h(huán)境不一樣。所以,我們先說明基本的IO操作及環(huán)境。
本文是在《UNIX網(wǎng)絡(luò)編程 卷1:套接字聯(lián)網(wǎng)API》6.2節(jié)"I/O 模型 "的基礎(chǔ)上,即UNIX/LINUX環(huán)境下的網(wǎng)絡(luò) IO環(huán)境下的理解,它里面給出的例子是讀取(接收)網(wǎng)絡(luò)UDP數(shù)據(jù)。下面簡單寫寫自己對這些IO模型的理解。
1、IO
IO (Input/Output,輸入/輸出)即數(shù)據(jù)的讀取(接收)或?qū)懭?#xff08;發(fā)送)操作,通常用戶進(jìn)程中的一個(gè)完整IO分為兩階段:用戶進(jìn)程空間<-->內(nèi)核空間、內(nèi)核空間<-->設(shè)備空間(磁盤、網(wǎng)絡(luò)等)。IO有內(nèi)存IO、網(wǎng)絡(luò)IO和磁盤IO三種,通常我們說的IO指的是后兩者。
LINUX中進(jìn)程無法直接操作I/O設(shè)備,其必須通過系統(tǒng)調(diào)用請求kernel來協(xié)助完成I/O動(dòng)作;內(nèi)核會(huì)為每個(gè)I/O設(shè)備維護(hù)一個(gè)緩沖區(qū)。
對于一個(gè)輸入操作來說,進(jìn)程IO系統(tǒng)調(diào)用后,內(nèi)核會(huì)先看緩沖區(qū)中有沒有相應(yīng)的緩存數(shù)據(jù),沒有的話再到設(shè)備中讀取,因?yàn)樵O(shè)備IO一般速度較慢,需要等待;內(nèi)核緩沖區(qū)有數(shù)據(jù)則直接復(fù)制到進(jìn)程空間。
所以,對于一個(gè)網(wǎng)絡(luò)輸入操作通常包括兩個(gè)不同階段:
- 等待網(wǎng)絡(luò)數(shù)據(jù)到達(dá)網(wǎng)卡→讀取到內(nèi)核緩沖區(qū),數(shù)據(jù)準(zhǔn)備好;
- 從內(nèi)核緩沖區(qū)復(fù)制數(shù)據(jù)到進(jìn)程空間。
2、5種IO模型
《UNIX網(wǎng)絡(luò)編程》說得很清楚,5種IO模型分別是阻塞IO模型、非阻塞IO模型、IO復(fù)用模型、信號(hào)驅(qū)動(dòng)的IO模型、異步IO模型;前4種為同步IO操作,只有異步IO模型是異步IO操作。
下面這樣些圖,是它里面給出的例子:接收網(wǎng)絡(luò)UDP數(shù)據(jù)的流程在IO模型下的分析,在它的基礎(chǔ)上再加以簡單描述,以區(qū)分這些IO模型。搜索Java知音公眾號(hào),回復(fù)“后端面試”,送你一份Java面試題寶典
2-1、阻塞IO模型
進(jìn)程發(fā)起IO系統(tǒng)調(diào)用后,進(jìn)程被阻塞,轉(zhuǎn)到內(nèi)核空間處理,整個(gè)IO處理完畢后返回進(jìn)程。操作成功則進(jìn)程獲取到數(shù)據(jù)。
1、典型應(yīng)用:阻塞socket、Java BIO;
2、特點(diǎn):
- 進(jìn)程阻塞掛起不消耗CPU資源,及時(shí)響應(yīng)每個(gè)操作;
- 實(shí)現(xiàn)難度低、開發(fā)應(yīng)用較容易;
- 適用并發(fā)量小的網(wǎng)絡(luò)應(yīng)用開發(fā);
不適用并發(fā)量大的應(yīng)用:因?yàn)橐粋€(gè)請求IO會(huì)阻塞進(jìn)程,所以,得為每請求分配一個(gè)處理進(jìn)程(線程)以及時(shí)響應(yīng),系統(tǒng)開銷大。
2-2、非阻塞IO模型
進(jìn)程發(fā)起IO系統(tǒng)調(diào)用后,如果內(nèi)核緩沖區(qū)沒有數(shù)據(jù),需要到IO設(shè)備中讀取,進(jìn)程返回一個(gè)錯(cuò)誤而不會(huì)被阻塞;進(jìn)程發(fā)起IO系統(tǒng)調(diào)用后,如果內(nèi)核緩沖區(qū)有數(shù)據(jù),內(nèi)核就會(huì)把數(shù)據(jù)返回進(jìn)程。
對于上面的阻塞IO模型來說,內(nèi)核數(shù)據(jù)沒準(zhǔn)備好需要進(jìn)程阻塞的時(shí)候,就返回一個(gè)錯(cuò)誤,以使得進(jìn)程不被阻塞。搜索Java知音公眾號(hào),回復(fù)“后端面試”,送你一份Java面試題寶典
1、典型應(yīng)用:socket是非阻塞的方式(設(shè)置為NONBLOCK)
2、特點(diǎn):
- 進(jìn)程輪詢(重復(fù))調(diào)用,消耗CPU的資源;
- 實(shí)現(xiàn)難度低、開發(fā)應(yīng)用相對阻塞IO模式較難;
- 適用并發(fā)量較小、且不需要及時(shí)響應(yīng)的網(wǎng)絡(luò)應(yīng)用開發(fā);
2-3、IO復(fù)用模型
多個(gè)的進(jìn)程的IO可以注冊到一個(gè)復(fù)用器(select)上,然后用一個(gè)進(jìn)程調(diào)用該select, select會(huì)監(jiān)聽所有注冊進(jìn)來的IO;
如果select沒有監(jiān)聽的IO在內(nèi)核緩沖區(qū)都沒有可讀數(shù)據(jù),select調(diào)用進(jìn)程會(huì)被阻塞;而當(dāng)任一IO在內(nèi)核緩沖區(qū)中有可數(shù)據(jù)時(shí),select調(diào)用就會(huì)返回;
而后select調(diào)用進(jìn)程可以自己或通知另外的進(jìn)程(注冊進(jìn)程)來再次發(fā)起讀取IO,讀取內(nèi)核中準(zhǔn)備好的數(shù)據(jù)。
可以看到,多個(gè)進(jìn)程注冊IO后,只有另一個(gè)select調(diào)用進(jìn)程被阻塞。
1、典型應(yīng)用:select、poll、epoll三種方案,nginx都可以選擇使用這三個(gè)方案;Java NIO;
2、特點(diǎn):
- 專一進(jìn)程解決多個(gè)進(jìn)程IO的阻塞問題,性能好;Reactor模式;
- 實(shí)現(xiàn)、開發(fā)應(yīng)用難度較大;
- 適用高并發(fā)服務(wù)應(yīng)用開發(fā):一個(gè)進(jìn)程(線程)響應(yīng)多個(gè)請求;
3、select、poll、epoll
- Linux中IO復(fù)用的實(shí)現(xiàn)方式主要有select、poll和epoll:
- Select:注冊IO、阻塞掃描,監(jiān)聽的IO最大連接數(shù)不能多于FD_SIZE;
- Poll:原理和Select相似,沒有數(shù)量限制,但I(xiàn)O數(shù)量大掃描線性性能下降;
- Epoll :事件驅(qū)動(dòng)不阻塞,mmap實(shí)現(xiàn)內(nèi)核與用戶空間的消息傳遞,數(shù)量很大,Linux2.6后內(nèi)核支持;
2-4、信號(hào)驅(qū)動(dòng)IO模型
當(dāng)進(jìn)程發(fā)起一個(gè)IO操作,會(huì)向內(nèi)核注冊一個(gè)信號(hào)處理函數(shù),然后進(jìn)程返回不阻塞;當(dāng)內(nèi)核數(shù)據(jù)就緒時(shí)會(huì)發(fā)送一個(gè)信號(hào)給進(jìn)程,進(jìn)程便在信號(hào)處理函數(shù)中調(diào)用IO讀取數(shù)據(jù)。
特點(diǎn):回調(diào)機(jī)制,實(shí)現(xiàn)、開發(fā)應(yīng)用難度大;
2-5、異步IO模型
當(dāng)進(jìn)程發(fā)起一個(gè)IO操作,進(jìn)程返回(不阻塞),但也不能返回果結(jié);內(nèi)核把整個(gè)IO處理完后,會(huì)通知進(jìn)程結(jié)果。如果IO操作成功則進(jìn)程直接獲取到數(shù)據(jù)。
1、典型應(yīng)用:JAVA7 AIO、高性能服務(wù)器應(yīng)用
2、特點(diǎn):
- 不阻塞,數(shù)據(jù)一步到位;Proactor模式;
- 需要操作系統(tǒng)的底層支持,LINUX 2.5 版本內(nèi)核首現(xiàn),2.6 版本產(chǎn)品的內(nèi)核標(biāo)準(zhǔn)特性;
- 實(shí)現(xiàn)、開發(fā)應(yīng)用難度大;
- 非常適合高性能高并發(fā)應(yīng)用;
3、IO模型比較
3-1、阻塞IO調(diào)用和非阻塞IO調(diào)用、阻塞IO模型和非阻塞IO模型
注意這里的阻塞IO調(diào)用和非阻塞IO調(diào)用不是指阻塞IO模型和非阻塞IO模型:
- 阻塞IO調(diào)用 :在用戶進(jìn)程(線程)中調(diào)用執(zhí)行的時(shí)候,進(jìn)程會(huì)等待該IO操作,而使得其他操作無法執(zhí)行。
- 非阻塞IO調(diào)用:在用戶進(jìn)程中調(diào)用執(zhí)行的時(shí)候,無論成功與否,該IO操作會(huì)立即返回,之后進(jìn)程可以進(jìn)行其他操作(當(dāng)然如果是讀取到數(shù)據(jù),一般就接著進(jìn)行數(shù)據(jù)處理)。
這個(gè)直接理解就好,進(jìn)程(線程)IO調(diào)用會(huì)不會(huì)阻塞進(jìn)程自己。所以這里兩個(gè)概念是相對調(diào)用進(jìn)程本身狀態(tài)來講的。
從上面對比圖片來說,阻塞IO模型是一個(gè)阻塞IO調(diào)用,而非阻塞IO模型是多個(gè)非阻塞IO調(diào)用+一個(gè)阻塞IO調(diào)用,因?yàn)槎鄠€(gè)IO檢查會(huì)立即返回錯(cuò)誤,不會(huì)阻塞進(jìn)程。
而上面也說過了,非阻塞IO模型對于阻塞IO模型來說區(qū)別就是,內(nèi)核數(shù)據(jù)沒準(zhǔn)備好需要進(jìn)程阻塞的時(shí)候,就返回一個(gè)錯(cuò)誤,以使得進(jìn)程不被阻塞。
3-2、同步IO和異步IO
- 同步IO:導(dǎo)致請求進(jìn)程阻塞,直到I/O操作完成。
- 異步IO:不導(dǎo)致請求進(jìn)程阻塞。
上面兩個(gè)定義是《UNIX網(wǎng)絡(luò)編程 卷1:套接字聯(lián)網(wǎng)API》給出的。這不是很好理解,我們來擴(kuò)展一下,先說說同步和異步,同步和異步關(guān)注的是雙方的消息通信機(jī)制:
- 同步:雙方的動(dòng)作是經(jīng)過雙方協(xié)調(diào)的,步調(diào)一致的。
- 異步:雙方并不需要協(xié)調(diào),都可以隨意進(jìn)行各自的操作。
這里我們的雙方是指,用戶進(jìn)程和IO設(shè)備;明確同步和異步之后,我們在上面網(wǎng)絡(luò)輸入操作例子的基礎(chǔ)上,進(jìn)行擴(kuò)展定義:
- 同步IO:用戶進(jìn)程發(fā)出IO調(diào)用,去獲取IO設(shè)備數(shù)據(jù),雙方的數(shù)據(jù)要經(jīng)過內(nèi)核緩沖區(qū)同步,完全準(zhǔn)備好后,再復(fù)制返回到用戶進(jìn)程。而復(fù)制返回到用戶進(jìn)程會(huì)導(dǎo)致請求進(jìn)程阻塞,直到I/O操作完成。
- 異步IO:用戶進(jìn)程發(fā)出IO調(diào)用,去獲取IO設(shè)備數(shù)據(jù),并不需要同步,內(nèi)核直接復(fù)制到進(jìn)程,整個(gè)過程不導(dǎo)致請求進(jìn)程阻塞。
所以, 阻塞IO模型、非阻塞IO模型、IO復(fù)用模型、信號(hào)驅(qū)動(dòng)的IO模型者為同步IO模型,只有異步IO模型是異步IO。
END
我知道你 “在看” 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的【多线程】0.理解一下5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【c++】15.订阅消息后转化为prot
- 下一篇: 【自动驾驶】2.车载以太网 - SOME