這樣講解Linux的五種io模型,應(yīng)該通俗易懂
今天分享Linux系統(tǒng)的io模型。Linux總共有5種io模型,分別是:
blocking IO 阻塞IO模型 On Blocking IO 非阻塞IO模型 IO multiplexing 多路復(fù)用IO模型 singnal dirven 信號(hào)驅(qū)動(dòng)IO模型 asyn 異步IO模型
我們首先來(lái)了解一下幾個(gè)基本的概念:
阻塞:阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起(線程進(jìn)入非可執(zhí)行狀態(tài),在這個(gè)狀態(tài)下,cpu不會(huì)給線程分配時(shí)間片,即線程暫停運(yùn)行)。函數(shù)只有在得到結(jié)果之后才會(huì)返回。換成一句白話,可以這樣說(shuō):調(diào)用我(函數(shù)),我(函數(shù))沒(méi)有接收完數(shù)據(jù)或者沒(méi)有得到結(jié)果之前,我不會(huì)返回。 非阻塞:非阻塞和阻塞的概念相對(duì)應(yīng),指在不能立刻得到結(jié)果之前,該函數(shù)不會(huì)阻塞當(dāng)前線程,而會(huì)立刻返回。換成一句白話,可以這樣說(shuō):調(diào)用我(函數(shù)),我(函數(shù))立即返回,通過(guò)select通知調(diào)用者 同步:所謂同步,就是在發(fā)出一個(gè)功能調(diào)用時(shí),在沒(méi)有得到結(jié)果之前,該調(diào)用就不返回。也就是必須一件一件事做,等前一件做完了才能做下一件事。換成一句白話,可以這樣說(shuō):我調(diào)用一個(gè)功能,該功能沒(méi)有結(jié)束前,我死等結(jié)果。 異步:異步的概念和同步相對(duì)。當(dāng)一個(gè)異步過(guò)程調(diào)用發(fā)出后,調(diào)用者不能立刻得到結(jié)果。實(shí)際處理這個(gè)調(diào)用的部件在完成后,通過(guò)狀態(tài)、通知和回調(diào)來(lái)通知調(diào)用者。換成一句白話,可以這樣說(shuō):我調(diào)用一個(gè)功能,不需要知道該功能結(jié)果,該功能有結(jié)果后通知我(回調(diào)通知)
阻塞IO
簡(jiǎn)單看下執(zhí)行流程:

流程:在整個(gè)過(guò)程中,當(dāng)用戶(hù)進(jìn)程進(jìn)行系統(tǒng)調(diào)用時(shí),內(nèi)核就開(kāi)始了I/O的第一個(gè)階段,準(zhǔn)備數(shù)據(jù)到緩沖區(qū)中,當(dāng)數(shù)據(jù)都準(zhǔn)備完成后,則將數(shù)據(jù)從內(nèi)核緩沖區(qū)中拷貝到用戶(hù)進(jìn)程的內(nèi)存中,這時(shí)用戶(hù)進(jìn)程才解除block的狀態(tài)重新運(yùn)行。
非阻塞IO模型

通過(guò)上圖流程圖,大致經(jīng)歷兩個(gè)階段:
等待數(shù)據(jù)階段:未阻塞, 用戶(hù)進(jìn)程需要盲等,不停的去輪詢(xún)內(nèi)核。 數(shù)據(jù)復(fù)制階段:阻塞,此時(shí)進(jìn)行數(shù)據(jù)復(fù)制。在這兩個(gè)階段中,用戶(hù)進(jìn)程只有在數(shù)據(jù)復(fù)制階段被阻塞了,而等待數(shù)據(jù)階段沒(méi)有阻塞,但是用戶(hù)進(jìn)程需要盲等,不停地輪詢(xún)內(nèi)核,看數(shù)據(jù)是否準(zhǔn)備好。
IO多路復(fù)用

從上圖可以看到在I/O復(fù)用模型中,由于同步非阻塞方式需要不斷主動(dòng)輪詢(xún),輪詢(xún)占據(jù)了很大一部分過(guò)程,輪詢(xún)會(huì)消耗大量的CPU時(shí)間,而 “后臺(tái)” 可能有多個(gè)任務(wù)在同時(shí)進(jìn)行,
相比于阻塞IO模型,多路復(fù)用只是多了一個(gè)select/poll/epoll函數(shù)。select函數(shù)會(huì)不斷地輪詢(xún)自己所負(fù)責(zé)的文件描述符/套接字的到達(dá)狀態(tài),當(dāng)某個(gè)套接字就緒時(shí),就對(duì)這個(gè)套接字進(jìn)行處理。select負(fù)責(zé)輪詢(xún)等待,recvfrom負(fù)責(zé)拷貝。當(dāng)用戶(hù)進(jìn)程調(diào)用該select,select會(huì)監(jiān)聽(tīng)所有注冊(cè)好的IO,如果所有IO都沒(méi)注冊(cè)好,調(diào)用進(jìn)程就阻塞。
對(duì)于客戶(hù)端來(lái)說(shuō),一般感受不到阻塞,因?yàn)檎?qǐng)求來(lái)了,可以用放到線程池里執(zhí)行;但對(duì)于執(zhí)行select的操作系統(tǒng)而言,是阻塞的,需要阻塞地等待某個(gè)套接字變?yōu)榭勺x。
IO多路復(fù)用其實(shí)是阻塞在select,poll,epoll這類(lèi)系統(tǒng)調(diào)用上的,復(fù)用的是執(zhí)行select,poll,epoll的線程。
從整個(gè)IO過(guò)程來(lái)看,他們都是順序執(zhí)行的,因此可以歸為同步模型(synchronous)。都是進(jìn)程主動(dòng)等待且向內(nèi)核檢查狀態(tài)。
信號(hào)驅(qū)動(dòng)IO

從上圖可以看出,只有在I/O執(zhí)行的第二階段阻塞了用戶(hù)進(jìn)程,而在第一階段是沒(méi)有阻塞的。該模型在I/O執(zhí)行的第一階段,當(dāng)數(shù)據(jù)準(zhǔn)備完成之后,會(huì)主動(dòng)的通知用戶(hù)進(jìn)程數(shù)據(jù)已經(jīng)準(zhǔn)備完成,即對(duì)用戶(hù)進(jìn)程做一個(gè)回調(diào)。該通知分為兩種,一為水平觸發(fā),即如果用戶(hù)進(jìn)程不響應(yīng)則會(huì)一直發(fā)送通知,二為邊緣觸發(fā),即只通知一次。
該模型也分為兩個(gè)階段:
數(shù)據(jù)準(zhǔn)備階段:未阻塞,當(dāng)數(shù)據(jù)準(zhǔn)備完成之后,會(huì)主動(dòng)的通知用戶(hù)進(jìn)程數(shù)據(jù)已經(jīng)準(zhǔn)備完成,對(duì)用戶(hù)進(jìn)程做一個(gè)回調(diào)。 數(shù)據(jù)拷貝階段:阻塞用戶(hù)進(jìn)程,等待數(shù)據(jù)拷貝。
異步IO

就是用戶(hù)進(jìn)程發(fā)起系統(tǒng)調(diào)用后,立刻就可以開(kāi)始去做其他的事情,然后直到I/O數(shù)據(jù)準(zhǔn)備好并復(fù)制完成后,內(nèi)核會(huì)給用戶(hù)進(jìn)程發(fā)送通知,告訴用戶(hù)進(jìn)程操作已經(jīng)完成了。
特點(diǎn):
異步I/O執(zhí)行的兩個(gè)階段都不會(huì)阻塞讀寫(xiě)操作,由內(nèi)核完成。 完成后內(nèi)核將數(shù)據(jù)放到指定的緩沖區(qū),通知應(yīng)用程序來(lái)取。
總結(jié)
阻塞IO和非阻塞IO的區(qū)別:數(shù)據(jù)準(zhǔn)備的過(guò)程中,進(jìn)程是否阻塞。
同步IO和異步IO的區(qū)別:數(shù)據(jù)拷貝的過(guò)程中,進(jìn)程是否阻塞。
從效率上來(lái)說(shuō),可以簡(jiǎn)單理解為阻塞IO<非阻塞IO<多路復(fù)用IO<信號(hào)驅(qū)動(dòng)IO<異步IO。從同步和異步來(lái)說(shuō),只有異步IO模型是異步的,其他均為同步。
推薦閱讀:
為 Linux 愛(ài)好者打造的極簡(jiǎn) Mac 終端
5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機(jī),樹(shù)莓派,等等。在公眾號(hào)內(nèi)回復(fù)「1024」,即可免費(fèi)獲取!!


