溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步

發(fā)布時(shí)間:2021-10-13 15:21:21 來源:億速云 閱讀:224 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步”吧!

在Unix網(wǎng)絡(luò)編程中,史蒂文斯給出了5種IO編程模型,其中最重點(diǎn)、也最常用的是多路復(fù)用模型(Multiplexing)。 這5種模型分別為:

  • 阻塞式IO

  • 非阻塞式IO

  • IO多路復(fù)用(multiplexing io),基于select/poll/epoll

  • 信號驅(qū)動(dòng)式IO SIGIO

  • 異步IO(posix aio_abi和libaio)

想要說明清楚這幾個(gè)模型,一個(gè)很好的方式是把網(wǎng)絡(luò)IO分為兩個(gè)階段來理解。第一階段,從客戶端向服務(wù)端發(fā)送請求開始,到數(shù)據(jù)從網(wǎng)絡(luò)傳輸?shù)竭_(dá),完全準(zhǔn)備好為止。第二階段,數(shù)據(jù)從內(nèi)核空間復(fù)制到程序緩存(即用戶空間),這個(gè)階段才是應(yīng)用真正執(zhí)行recvfrom系統(tǒng)調(diào)用的階段。在第一階段,程序要么阻塞在recvfrom調(diào)用上,要么阻塞在select之類的方法上,或者干其他的事情去了(輪詢、異步等)。

如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步

有了這個(gè)基本認(rèn)知,我們再來逐個(gè)審視這幾種模型。

阻塞式I/O模型

阻塞式IO(blocking I/O)是最基本的IO模型,也是日常使用中默認(rèn)的模式。

如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步

如上圖,應(yīng)用發(fā)出請求,試圖執(zhí)行recvfrom系統(tǒng)調(diào)用,以獲取數(shù)據(jù),由于數(shù)據(jù)還沒準(zhǔn)備好(也許服務(wù)端才開始處理請求),當(dāng)前請求線程被阻塞,只能傻傻的等待,直到數(shù)據(jù)可讀或者拋出異常。如果是單線程應(yīng)用,主線程掛起,CPU空置。如果是多線程,當(dāng)前線程掛起,CPU切換時(shí)間片去執(zhí)行其他線程。

非阻塞式IO模型

一般的Socket對象都會有一個(gè)setblocking(False)或者ConfigureBlocing(false)之類的方法,將當(dāng)前IO線程設(shè)置成非阻塞模式。

如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步

如圖,當(dāng)socket設(shè)置為nonblocking時(shí),在一階段(數(shù)據(jù)準(zhǔn)備階段,還記得前面說的二階段IO么,這里派上了用場)線程會不斷的發(fā)起recvfrom輪詢,如果還沒有準(zhǔn)備好數(shù)據(jù),會得到一個(gè)EWouldBLOCK錯(cuò)誤信號,直到數(shù)據(jù)準(zhǔn)備好之后,開始真正執(zhí)行recvfrom拉取數(shù)據(jù)。輪詢會極大的消耗CPU時(shí)間,所以這種模型極少用到。

IO多路復(fù)用

I/O復(fù)用,即I/O multiplexing,這是一種基于select函數(shù)的編程模型,也是最常用的一種。有些人喜歡把它稱作異步阻塞模型,我覺得這種叫法很容易讓人產(chǎn)生誤解,實(shí)際上這個(gè)模型和所謂的異步I/O沒有半毛錢關(guān)系。

如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步

如上圖,在第一階段,我們可以通過select函數(shù)注冊多路IO對象。每一個(gè)注冊的IO對象都會阻塞在select函數(shù)上,直到IO對象的狀態(tài)發(fā)生改變。此時(shí)數(shù)據(jù)已經(jīng)準(zhǔn)備好讀/寫。調(diào)度器遍歷這些IO對象,返回準(zhǔn)備好讀/寫的IO對象。緊接著進(jìn)入第二階段,開始對準(zhǔn)備好的IO對象調(diào)用recvfrom函數(shù)。

對于多路復(fù)用模型,Java NIO基于select庫實(shí)現(xiàn)了調(diào)度器Selector,python的selectors模塊分別提供了基于selectpoll以及epoll庫的封裝對象。

通過以上過程,我們還可以看到,其實(shí)IO多路復(fù)用阻塞IO很相似,基本兩個(gè)階段都在阻塞狀態(tài)。只不過前者第一階段阻塞在select函數(shù)上,第二階段阻塞在recvfrom調(diào)用上;而后者全程阻塞在recvfrom上。而且IO多路復(fù)用由于需要注冊、遍歷IO對象,其實(shí)涉及到更多的步驟開銷。但是多路復(fù)用的優(yōu)勢正在于可以同時(shí)對接多個(gè)IO對象,結(jié)合多線程技術(shù),可以帶來很大的靈活性。

異步IO模型

前面提到的三種模型,本質(zhì)上在真正的IO階段(第二階段),都會阻塞。而在異步IO模型中,應(yīng)用發(fā)出數(shù)據(jù)請求后,不再等待,直接返回。期間線程也不會阻塞。之后由內(nèi)核處理兩個(gè)階段IO,然后給應(yīng)用發(fā)送信號,程序直接獲取數(shù)據(jù)。

如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步

基于Unix系統(tǒng)有一個(gè)POSIX異步IO庫——aio_abi,以及一個(gè)第三方庫aiolib,后者可能更加知名。異步IO模型非常復(fù)雜,一般很少見到。另外我也有一些疑惑,python中的asyncio包提出的協(xié)程概念,和這里的異步IO是否為同一件事物。史蒂文斯在這里描述的異步明顯需要基于系統(tǒng)內(nèi)核的相關(guān)實(shí)現(xiàn),和asyncio這種單純的編程概念,大概說的不是一個(gè)層級的東西吧。

隱喻

最后還是說一個(gè)比喻吧。如果把IO模型比作網(wǎng)購,在你提交訂單的一刻到快遞員將貨物帶到你家小區(qū)門口期間,可看作一階段IO。之后小哥給你打電話:“你的快遞,快開門”,這相當(dāng)于數(shù)據(jù)準(zhǔn)備好了,并發(fā)送了通知。之后,你跑到門口將快遞一件一件搬到家里,這是第二階段。

阻塞模型相當(dāng)于你提了訂單,就不吃不喝,只等著快遞,直到小哥給你打電話,然后吭哧吭哧把快遞搬到家,你才開始吃喝、睡覺等。非阻塞模型下,你提交訂單后就開始自由行動(dòng)了。但是仍然會每隔幾分鐘跑到小區(qū)門口看看快遞到了沒(輪詢),一直把自己搞得精疲力盡。直到小哥給你打電話,你把快遞搬回家才算消停。多路復(fù)用模型下,你同時(shí)提交了多個(gè)訂單,但不再傻傻的朝門口來回跑了,而是緊緊盯著菜鳥裹裹信息(阻塞在select),直到其上顯示至少有一個(gè)快遞到了,你會嗖的跑過去,當(dāng)然,快遞仍然自己搬(recvfrom阻塞)。異步模型下,你雇了一個(gè)萬能管家吉福斯,你只要下完訂單,就不用操心了,他會打點(diǎn)好一切,最后他會把快遞按照你們約定的地點(diǎn)、方式,直接送到你的手上。

到此,相信大家對“如何理解常見的IO模型:阻塞、非阻塞、多路復(fù)用、異步”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI