淺談I/O模型

一:概念的理解:?

首先在網(wǎng)絡(luò)編程的時候,我們常常見到同步/異步,阻塞/非阻塞四中調(diào)用方式:

1同步和異步主要針對C(client)端?

同步:?

所謂的同步,就是在c端發(fā)出一個功能調(diào)用時,在沒有得到結(jié)果之前,該調(diào)用步返回,也就是說必須一件一件事做,等前一件事完了之后才做后一件事。?

如:普通的B/S模式(同步):提交請求->等待服務(wù)器處理->處理完畢返回,這期間客戶端瀏覽器不能干任何事

異步:?

與同步相對。當(dāng)C端一個異步過程調(diào)用發(fā)出之后,調(diào)用者不能立即得到結(jié)果,實(shí)際處理這個調(diào)用的部件在完成后,通過狀態(tài),通知和回調(diào)來通知調(diào)用者。?

如:請求通過事件觸發(fā)->服務(wù)器處理(瀏覽器仍然可以做其他事情)->處理完畢

阻塞和非阻塞主要針對S端(server)

阻塞?

阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會被掛起(線程進(jìn)入非可執(zhí)行狀態(tài),在這個狀態(tài),cpu不會分配時間片,線程暫停運(yùn)行)函數(shù)只有得到結(jié)果返回。?

阻塞調(diào)用和同步調(diào)用的區(qū)別:對同步來說,很多時候當(dāng)前線程還是激活的,只是邏輯上沒有返回,如,在socket編程中調(diào)用recv函數(shù),如果緩沖區(qū)沒有數(shù)據(jù),這個函數(shù)就會一直等待,直到有數(shù)據(jù)返回。而此前當(dāng)前線程還有可能繼續(xù)處理各種各樣的消息。

阻塞的例子:比如去取A樓一層(假設(shè)是內(nèi)核緩沖區(qū))取快遞,但是比不知道什么時候來,你有不能干別的事情,只能死等著但是可以睡覺(進(jìn)程處于休眠狀態(tài)),因?yàn)槟阒揽爝f把貨送來時一定會給比大電話

非阻塞:?

非阻塞與阻塞概念想對應(yīng),指在不能立即得到結(jié)果之前,該函數(shù)不會阻塞當(dāng)前線程,而會立即返回。

非阻塞的例子:還是等快遞,如果用輪詢的方式,每隔5分鐘去A樓一層(內(nèi)核緩沖區(qū))去看快遞來了沒,沒來,立即返回,如果快遞來了,就放到A樓一層,等你去取。

對象是否處于阻塞模式和函數(shù)是不是阻塞調(diào)用有很強(qiáng)的相關(guān)性,但不是一一對應(yīng)的。阻塞對象上可以有非阻塞的調(diào)用方式,我們可以通過輪詢狀態(tài),在適當(dāng)?shù)臅r候調(diào)用阻塞函數(shù),就可以避免阻塞,而對于非阻塞對象,調(diào)用函數(shù)可以進(jìn)入阻塞調(diào)用,對于select:?

1:同步?

我客戶端(C端調(diào)用者)一個功能,該功能沒有結(jié)束前,我死等結(jié)果。?

2:異步,我(c端調(diào)用者)調(diào)用一個功能,不知道該功能結(jié)果,該功能有結(jié)果后通知我,即回調(diào)通知

同步和異步主要針對c端,但是跟s端不是完全沒關(guān)系,同步和異步必須s端配合才能實(shí)現(xiàn),同步和異步由c端控制,但是s端是否為阻塞還是非阻塞,c端不關(guān)心。

3:阻塞,就是調(diào)用我(s端被調(diào)用者,函數(shù)),我(s端被調(diào)用者,函數(shù))沒有完全接受完數(shù)據(jù)或者沒有得到結(jié)果之前,我不會返回。

4:非阻塞,就是調(diào)用我(s端被調(diào)用者,函數(shù)),我(s端被調(diào)用者,函數(shù))立即返回,通過select通知調(diào)用者

二:同步I/O和異步I/O?

同步I/O與異步I/O的區(qū)別在與數(shù)據(jù)訪問的時候進(jìn)程是否阻塞?

阻塞I/O與非阻塞I/O的區(qū)別在與:應(yīng)該程序的調(diào)用是否立即返回。

阻塞和非阻塞是指server端的進(jìn)程訪問的數(shù)據(jù)如果尚未就緒,進(jìn)程是否需要等待,簡單說這相當(dāng)于函數(shù)內(nèi)部的實(shí)現(xiàn)區(qū)別,也就是未就緒時時直接返回還是等待就緒。

就同步和異步是指client端訪問數(shù)據(jù)的機(jī)制,同步一般指主動請求并等待I/O操作完畢的方式,當(dāng)數(shù)據(jù)就緒后再讀寫額時候必須阻塞,異步則指主動請求數(shù)據(jù)后便可以繼續(xù)處理其他任務(wù),隨后等待I/O,操作完畢的通知。

三:五種I/O模型:?

1)阻塞I/O?

2)非阻塞I/O?

3)I/O復(fù)用(select和poll)?

4)信號驅(qū)動I/O(SIGIO)?

5)異步I/O?

前四中是同步,最后一種是異步。?

阻塞I/O模型:?

簡介:進(jìn)程會一直阻塞,直到數(shù)據(jù)拷貝完成?

應(yīng)用程序調(diào)用一個I/O函數(shù),導(dǎo)致應(yīng)用程序阻塞,等待數(shù)據(jù)準(zhǔn)備好,如果數(shù)據(jù)沒有準(zhǔn)備好,一直等待。。數(shù)據(jù)準(zhǔn)備好,從內(nèi)核拷貝到用戶空間,I/O函數(shù)返回成功

阻塞I/O模型圖:在調(diào)用recv()/recvfrom()函數(shù),發(fā)生在內(nèi)核中等待數(shù)據(jù)和復(fù)制數(shù)據(jù)過程。?


當(dāng)調(diào)用recv()函數(shù)時,系統(tǒng)首先檢查是否有準(zhǔn)備好的數(shù)據(jù),如果數(shù)據(jù)沒有準(zhǔn)備好,那么系統(tǒng)就處于等待狀態(tài),當(dāng)數(shù)據(jù)準(zhǔn)備好后,將數(shù)據(jù)從系統(tǒng)緩沖區(qū)復(fù)制到用戶空間,然后函數(shù)返回。在套接應(yīng)用程序中,當(dāng)調(diào)用recv()函數(shù)時,未必用戶空間就已經(jīng)存在數(shù)據(jù),那么此時recv()函數(shù)處于等待狀態(tài)?

非阻塞I/O模型:?

簡介:我們把一個套接口設(shè)置為非阻塞就是告訴內(nèi)存,當(dāng)所請求的I/O操作無法完成時,不要進(jìn)程睡眠,而是返回一個錯誤,I/O函數(shù)會不斷的測試數(shù)據(jù)是否準(zhǔn)備好,沒有準(zhǔn)備好,繼續(xù)測試,直到數(shù)據(jù)準(zhǔn)備好為止。在測試的過程中會占用大量的CPU時間。?


I/O多路復(fù)用模型:?

簡介:主要是select和epoll;對于一個I/O端口,兩次調(diào)用,兩次返回,比阻塞I/O并沒有什么優(yōu)勢,只是能實(shí)現(xiàn)同時對多個I/O端口進(jìn)行監(jiān)聽。

I/O多路復(fù)用模型會調(diào)用select,poll函數(shù),這幾個函數(shù)也會使進(jìn)程阻塞,但是和阻塞I/O不同的,這個函數(shù)可以同時阻塞多個I/O操作,而且可以同時對多個讀操作,多個寫操作的I/O函數(shù)進(jìn)行檢測,直到有數(shù)據(jù)可讀或可寫時,才真正調(diào)用I/O操作函數(shù)。?


IO多路復(fù)用適用場合:

當(dāng)客戶端處理多個描述符時(請求)(一般是交互式輸入和網(wǎng)絡(luò)套接口),必須使用I/O復(fù)用

當(dāng)一個客戶端同時處理多個套接字時,此情況可能的但很少出現(xiàn)

當(dāng)一個TCP服務(wù)器既要處理監(jiān)聽套接字,又要處理已連接套接字,一般也要用到I/O復(fù)用 (使用最多的場景)

當(dāng)一個服務(wù)器即要處理TCP,又要處理UDP,一般要使用I/O復(fù)用

當(dāng)一個服務(wù)器要處理多個服務(wù)或多個協(xié)議,一般要使用I/O復(fù)用


信號驅(qū)動I/O?

簡介:兩次調(diào)用,兩次返回?

首先允許套接口進(jìn)行信號驅(qū)動I/O,并安裝一個信號處理函數(shù),進(jìn)程繼續(xù)運(yùn)行并不阻塞。當(dāng)數(shù)據(jù)準(zhǔn)備好時,進(jìn)程會收到一個SIGIO信號,可以在信號處理函數(shù)中調(diào)用I/O操作函數(shù)處理數(shù)據(jù)。?


異步I/O模型:?

簡介:數(shù)據(jù)拷貝的時候進(jìn)程無需阻塞?

當(dāng)一個異步過程調(diào)用發(fā)出后,調(diào)用者不能立刻得到結(jié)果。實(shí)際處理這個調(diào)用的部件在完成后,通過狀態(tài),通知和回調(diào)通知調(diào)用者輸入輸出操作。?


四:五種I/O模型的比較


五:I/O模型的具體實(shí)現(xiàn)

主要實(shí)現(xiàn)方式有以下幾種:

Select:Linux實(shí)現(xiàn)對應(yīng),I/O復(fù)用模型,BSD4.2最早實(shí)現(xiàn)

Poll:Linux實(shí)現(xiàn),對應(yīng)I/O復(fù)用模型,System V unix最早實(shí)現(xiàn)? (改進(jìn)版的select)

Epoll:Linux實(shí)現(xiàn),對應(yīng)I/O復(fù)用模型,具有信號驅(qū)動I/O模型的某些特性

Kqueue:FreeBSD實(shí)現(xiàn),對應(yīng)I/O復(fù)用模型,具有信號驅(qū)動I/O模型某些特性

/dev/poll:SUN的Solaris實(shí)現(xiàn),對應(yīng)I/O復(fù)用模型,具有信號驅(qū)動I/O模型的某些特性

Iocp? Windows實(shí)現(xiàn),對應(yīng)第5種(異步I/O)模型


六:select/poll/epoll的比較:


1,select

優(yōu)點(diǎn)

Select:POSIX所規(guī)定,目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優(yōu)點(diǎn),本質(zhì)上是通過設(shè)置或者檢查存放fd標(biāo)志位的數(shù)據(jù)結(jié)構(gòu)來進(jìn)行下一步處理?

缺點(diǎn)

單個進(jìn)程可監(jiān)視的fd數(shù)量被限制,即能監(jiān)聽端口的數(shù)量有限? cat /proc/sys/fs/file-max?

對socket是線性掃描,即采用輪詢的方法,效率較低?

select 采取了內(nèi)存拷貝方法來實(shí)現(xiàn)內(nèi)核將 FD 消息通知給用戶空間,這樣一個用來存放大量fd的數(shù)據(jù)結(jié)構(gòu),這樣會使得用戶空間和內(nèi)核空間在傳遞該結(jié)構(gòu)時復(fù)制開銷大?

2, poll

本質(zhì)上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間,然后查詢每個fd對應(yīng)的設(shè)備狀態(tài)

其沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲的

大量的fd的數(shù)組被整體復(fù)制于用戶態(tài)和內(nèi)核地址空間之間,而不管這樣的復(fù)制是不是有意義

poll特點(diǎn)是“水平觸發(fā)”,如果報告了fd后,沒有被處理,那么下次poll時會再次報告該fd? (通知多次)

邊緣觸發(fā):只通知一次,性能更好

3,epoll

在Linux 2.6內(nèi)核中提出的select和poll的增強(qiáng)版本

優(yōu)點(diǎn):

支持水平觸發(fā)LT和邊緣觸發(fā)ET,最大的特點(diǎn)在于邊緣觸發(fā),它只告訴進(jìn)程哪些fd剛剛變?yōu)榫托钁B(tài),并且只會通知一次

使用“事件”的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內(nèi)核就會采用類似callback的回調(diào)機(jī)制來激活該fd,epoll_wait便可以收到通知

沒有最大并發(fā)連接的限制:能打開的FD的上限遠(yuǎn)大于1024(1G的內(nèi)存能監(jiān)聽約10萬個端口)

效率提升:非輪詢的方式,不會隨著FD數(shù)目的增加而效率下降;只有活躍可用的FD才會調(diào)用callback函數(shù),即epoll最大的優(yōu)點(diǎn)就在于它只管理“活躍”的連接,而跟連接總數(shù)無關(guān)

內(nèi)存拷貝,利用mmap(Memory Mapping,內(nèi)存映射)加速與內(nèi)核空間的消息傳遞;即epoll使用mmap減少復(fù)制開銷

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容