LinuxIO模型概述

2021-07-08 12:14:03 字數 2495 閱讀 2991

前言

乙個socket程序進行一次read可以分成兩個階段,等待資料是否準備好,以及資料從核心copy到使用者空間。 我們舉個例子,肚子餓了要去小吃街吃拉麵,在我們正式開始吃麵之前需要1.先等拉麵師傅做好面,2.然後把做好的面放到我們的桌子上。

阻塞和非阻塞

阻塞和非阻塞,主要是針對事情的本身,指做一件事後能不能返回乙個結果。

阻塞就是一直等待到事情做完才返回,非阻塞就是立馬返回乙個訊息(沒做好或者已經做好)

。如果是阻塞程序read一直等待,程序控制權就沒了,要阻塞兩個階段,資料到來和資料從核心copy到程序緩衝區。

非阻塞則是read一發出立馬返回乙個錯誤資訊,程式裡必須不斷去read直到資料到達返回可讀訊息,然後程序阻塞把資料從核心緩衝區copy到程序緩衝區,實際阻塞的是後面取資料的階段。

繼續上面的例子,下單之後等待師傅做麵的過程,我們可以一直傻乎乎地在旁邊等著師傅做好。也可以先去其他地方玩玩,然後時不時一會兒跑回來問下師傅有沒有做好,有沒有做好...前者就是阻塞,後者就是非阻塞。等到師傅師傅做好了,我把麵端回來到桌子上,這部分也是阻塞的。

對於阻塞和非阻塞而言,如果針對乙個io,非阻塞根本沒阻塞的效率高。而且相對於阻塞而言,非阻塞是輪詢要發出很多次系統呼叫的,而且很多次都是空輪詢,看起來毫無優勢可言。但是非阻塞io因為等待資料階段是非阻塞的,所以可以同時進行很多個io操作。 繼續上面的例子,我點完麵之後還想去吃小籠包,還有奶茶。如果是阻塞,那麼我必須等麵做好了,我再去奶茶店等奶茶,等奶茶好了再去等小籠包。如果是非阻塞,我點了面後,跑到奶茶店點奶茶,然後再去小籠包店點小籠包,然後開始輪著跑三家店是否準備好了,夠累的的吧?

io多路復用

儘管非阻塞支援同時多io,但是資源上還是很浪費,存在很多空輪詢。於是出現了一種新的io模型,叫做io多路復用模型,最早的就是select模型和poll模型,兩者開始的區別只是平台不同,而且前者有最大監控描述符限制,但是功能上差不多。select模型支援一次性監控一大堆感興趣的io事件發生的描述符集合,一旦有乙個或多個io準備就緒,就返回所有描述符集合。然後掃瞄返回列表,找到有可讀或者可寫的描述符,可能是乙個也可能多個,進行相應第二階段讀取或者寫入資料。

select模型呼叫的時候也是阻塞的,只是它支援多路io前提下減少了不必要的空輪詢。

繼續上面的例子,我為了能吃麵和奶茶,小籠包三家店輪著跑而累的氣喘吁吁,這時候小吃街上多了一塊大螢幕,裡面有各個店準備小吃的狀態,比如小籠包正在做,面已經做好了,等等,我就是只需要看著大螢幕就可以了,然後篩選下哪些是已經做好了,我就去店裡面取,再也不需要來回挨家挨戶跑了。這個大螢幕的出現就是select模型。

select模型最大的優點就是跨平台性好,估計也就只剩這個優點了。看看它的缺點,1. 首先支援的監控的描述符集合數量有限制,核心引數決定的。2. 每次select呼叫程序是阻塞的,並且需要把描述符集合從使用者態copy到核心態,一旦數量增加,資源消耗線性增加。3. select返回的描述符是沒有經過篩選的,上面有些有io需求,有些沒有。 還是採用上面的例子,儘管有了大螢幕,你還是得等,常常去看看大螢幕。其次大螢幕上對於那些沒做好的小吃對我是沒有用的,我只關注做好的,還得我人工篩選,有點笨。總之,一旦我買的東西很多很多,就會很麻煩。

更新的多路復用技術epoll出現了,幾乎沒有最大描述符數量限制,epoll實現很複雜,每個描述符註冊到核心裡,只需要一次,每個socket都是非阻塞,對於每個描述符都設計了callback,而且epoll返回的都是可用的描述符集合,不需要再掃瞄一遍尋找可io的描述符。epoll還支援兩種觸發模型,epoll水平觸發和邊緣觸發

同步和非同步

再說點同步和非同步的區別,這兩者主要是針對發起者而言,是指做發出指令要做一件事後是否撒手不管,

計算機上看是io系統呼叫後本身實現的乙個邏輯而已。 對於同步,就是發出指令要去做一件事,為了知道結果,所以可能一直去等待,或者不斷去輪詢是否做好。而非同步則是發出指令要做一件事,不管結果直接返回去做其它事情,然後等待通知,這就算是非同步。在計算機上看是針對程序發出io請求後與核心互動的過程。

同步就是io發出後程序還一直在關注io是否完成,要麼阻塞,要麼輪詢等待結果。而非同步是使用者程序發出io請求後立馬返回去做其它事情,直到核心等待資料並且把資料準備好通知程序算是非同步。重點就是在通知上!對於同步才會有阻塞或者非阻塞的概念,對於非同步,沒什麼阻塞和非阻塞了。

繼續上面的例子,去小吃街吃麵,如果是同步機制,點了面之後我就要麼一直等待著(同步阻塞),等待師傅把麵做好,或者我時不時一會兒跑過去問下師傅面做好了沒(同步非阻塞)。等到師傅面做好了,我再把麵端回桌子(這個過程由我自己完成,也算阻塞)。 如果是非同步機制,我在點麵的時候留了乙個手機號碼,然後告訴師傅我坐幾號桌,然後就可以安心去逛街了,等到師傅把麵做好了,師傅會自己把麵端到我指定的桌子上,然後發簡訊告訴我面已經按照我的要求準備好了,所以非同步的效率肯定是最好的。

總結一下:

1、同步阻塞:等待資料是否準備好:阻塞, 資料從核心copy到使用者空間:阻塞

2、同步非阻塞:等待資料是否準備好:非阻塞,但是需要很多空輪詢; 資料從核心copy到使用者空間:阻塞

3、select/poll:等待資料是否準備好:非阻塞,多路復用減少了不必要的空輪詢; 資料從核心copy到使用者空間:阻塞

4、非同步:通知機制

Linux IO模型漫談(2)

不管linux的io模型的阻塞同步分類是如何分類,幾種io模型的具體實現是確定的。這裡借用 unix 網路程式設計 卷一 的說明。這個模型也是最容易理解的 程式呼叫和我們基本的程式編寫是一致的 fd connect write fd read fd close fd 程式的read必須在write之...

Linux IO模型漫談(1)

linux將所有外部裝置都看做乙個檔案來進行操作。因此,linux對所有外部裝置的操作都可以看做是檔案的操作。檔案的操作當然需要有個標示描述它,這就是檔案描述符 file descriptor 我們說網路socket的read 是乙個io操作命令,具體流程是這樣的 應用程式呼叫read命令,通知核心...

Linux IO模型漫談(2)

不管linux的io模型的阻塞同步分類是如何分類,幾種io模型的具體實現是確定的。這裡借用 unix 網路程式設計 卷一 的說明。這個模型也是最容易理解的 程式呼叫和我們基本的程式編寫是一致的 fd connect write fd read fd close fd 程式的read必須在write之...