如何給女朋友解釋什麼是Linux的五種IO模型?
來源:漫話程式設計(ID:mhcoding)
漫小畫
擅長漫話
程小員
擅長程式設計
週日午後,剛剛放下手裡的電話,正在給剛剛的面試者寫評價。剛剛寫到『對Linux的基本IO模型理解不深』這句的時候,女朋友突然出現。
哈,這個面試者咋不知道IO模型呢,我都知道呢。
你怎麼知道呢,你給我說說。
上次你給我講過呀。
在Java中,主要有三種IO模型,分別是阻塞IO(BIO)、非阻塞IO(NIO)和 非同步IO(AIO)。
額、你說的這個是Java中提供的IO有關的API啊。並不是作業系統層面的IO模型呢。
這有啥區別嗎?他們有啥關係嗎?
Java中提供的IO有關的API,在檔案處理的時候,其實依賴作業系統層面的IO操作實現的。比如在Linux 2.6以後,Java中NIO和AIO都是通過epoll來實現的,而在Windows上,AIO是通過IOCP來實現的。
可以把Java中的BIO、NIO和AIO理解為是Java語言對作業系統的各種IO模型的封裝。程式設計師在使用這些API的時候,不需要關心作業系統層面的知識,也不需要根據不同作業系統編寫不同的程式碼。只需要使用Java的API就可以了。
哦。那這個我不懂,你給我講講吧。
好吧,那就給你簡單介紹一下吧。
嗯嗯,好的,講的好了的話,晚上給你做紅燒魚吃。
嗯嗯,好的。
在Linux(UNIX)作業系統中,共有五種IO模型,分別是:阻塞IO模型、非阻塞IO模型、IO複用模型、訊號驅動IO模型以及非同步IO模型。
既然提到晚上吃魚,那就通過釣魚的例子來解釋這五種IO模型吧。
到底什麼是IO
我們常說的IO,指的是檔案的輸入和輸出,但是在作業系統層面是如何定義IO的呢?到底什麼樣的過程可以叫做是一次IO呢?
拿一次磁碟檔案讀取為例,我們要讀取的檔案是儲存在磁碟上的,我們的目的是把它讀取到記憶體中。可以把這個步驟簡化成把資料從硬體(硬碟)中讀取到使用者空間中。
其實真正的檔案讀取還涉及到快取等細節,這裡就不展開講述了。關於使用者空間、核心空間以及硬體等的關係如果讀者不理解的話,可以通過釣魚的例子理解。
釣魚的時候,剛開始魚是在魚塘裡面的,我們的釣魚動作的最終結束標誌是魚從魚塘中被我們釣上來,放入魚簍中。
這裡面的魚塘就可以對映成磁碟,中間過渡的魚鉤可以對映成核心空間,最終放魚的魚簍可以對映成使用者空間。一次完整的釣魚(IO)操作,是魚(檔案)從魚塘(硬碟)中轉移(拷貝)到魚簍(使用者空間)的過程。
阻塞IO模型
我們釣魚的時候,有一種方式比較愜意,比較輕鬆,那就是我們坐在魚竿面前,這個過程中我們什麼也不做,雙手一直把著魚竿,就靜靜的等著魚兒咬鉤。一旦手上感受到魚的力道,就把魚釣起來放入魚簍中。然後再釣下一條魚。
對映到Linux作業系統中,這就是一種最簡單的IO模型,即阻塞IO。 阻塞 I/O 是最簡單的 I/O 模型,一般表現為程式或執行緒等待某個條件,如果條件不滿足,則一直等下去。條件滿足,則進行下一步操作。
應用程式通過系統呼叫 recvfrom
接收資料,但由於核心還未準備好資料包,應用程式就會阻塞住,直到核心準備好資料包,recvfrom
完成資料包復制工作,應用程式才能結束阻塞狀態。
這種釣魚方式相對來說比較簡單,對於釣魚的人來說,不需要什麼特製的魚竿,拿一根夠長的木棍就可以悠閒的開始釣魚了(實現簡單)。缺點就是比較耗費時間,比較適合那種對魚的需求量小的情況(併發低,時效性要求低)。
這個釣魚的人真傻,等魚咬鉤的時候可以做點別的事情呀。
嗯,你說的這種就是兩外一種IO模型了。
非阻塞IO模型
我們釣魚的時候,在等待魚兒咬鉤的過程中,我們可以做點別的事情,比如玩一把王者榮耀、看一集《延禧攻略》等等。但是,我們要時不時的去看一下魚竿,一旦發現有魚兒上鉤了,就把魚釣上來。
對映到Linux作業系統中,這就是非阻塞的IO模型。應用程式與核心互動,目的未達到之前,不再一味的等著,而是直接返回。然後通過輪詢的方式,不停的去問核心資料準備有沒有準備好。如果某一次輪詢發現資料已經準備好了,那就把資料拷貝到使用者空間中。
應用程式通過 recvfrom
呼叫不停的去和核心互動,直到核心準備好資料。如果沒有準備好,核心會返回error
,應用程式在得到error
後,過一段時間再傳送recvfrom
請求。在兩次傳送請求的時間段,程式可以先做別的事情。
這種方式釣魚,和阻塞IO比,所使用的工具沒有什麼變化,但是釣魚的時候可以做些其他事情,增加時間的利用率。
這樣確實好了一點了。魚兒上鉤之前我可以去淘寶挑兩條裙子。
額,但是你還是要時不時的關注魚竿的動向。
這還不好解決,買一個帶提醒功能的魚竿不就行了。
嗯,你說的又是另外一種IO模型了。
訊號驅動IO模型
我們釣魚的時候,為了避免自己一遍一遍的去檢視魚竿,我們可以給魚竿安裝一個報警器。當有魚兒咬鉤的時候立刻報警。然後我們再收到報警後,去把魚釣起來。
對映到Linux作業系統中,這就是訊號驅動IO。應用程式在讀取檔案時通知核心,如果某個 socket 的某個事件發生時,請向我發一個訊號。在收到訊號後,訊號對應的處理函式會進行後續處理。
應用程式預先向核心註冊一個訊號處理函式,然後使用者程式返回,並且不阻塞,當核心資料準備就緒時會傳送一個訊號給程式,使用者程式便在訊號處理函式中開始把資料拷貝的使用者空間中。
這種方式釣魚,和前幾種相比,所使用的工具有了一些變化,需要有一些定製(實現複雜)。但是釣魚的人就可以在魚兒咬鉤之前徹底做別的事兒去了。等著報警器響就行了。
嗯,這種方式最輕鬆啦。
是的。我問你啊,你還有什麼好的方法可以最短時間內釣更多的魚嗎?
這還能難倒我麼,同一時間擺放多個魚竿同時釣唄。
好聰明,你說的又是另外一種IO模型了。
IO複用模型
我們釣魚的時候,為了保證可以最短的時間釣到最多的魚,我們同一時間擺放多個魚竿,同時釣魚。然後哪個魚竿有魚兒咬鉤了,我們就把哪個魚竿上面的魚釣起來。
對映到Linux作業系統中,這就是IO複用模型。多個程式的IO可以註冊到同一個管道上,這個管道會統一和核心進行互動。當管道中的某一個請求需要的資料準備好之後,程式再把對應的資料拷貝到使用者空間中。
IO多路轉接是多了一個select
函式,多個程式的IO可以註冊到同一個select
上,當使用者程式呼叫該select
,select
會監聽所有註冊好的IO,如果所有被監聽的IO需要的資料都沒有準備好時,select
呼叫程式會阻塞。當任意一個IO所需的資料準備好之後,select
呼叫就會返回,然後程式在通過recvfrom
來進行資料拷貝。
這裡的IO複用模型,並沒有向核心註冊訊號處理函式,所以,他並不是非阻塞的。程式在發出select
後,要等到select
監聽的所有IO操作中至少有一個需要的資料準備好,才會有返回,並且也需要再次傳送請求去進行檔案的拷貝。
這種方式的釣魚,通過增加魚竿的方式,可以有效的提升效率。
奧,我太聰明瞭。上面這幾種我都聽懂了。
真的聽懂了麼,那我考考你:上面幾種哪個是非同步的,哪個是同步的?
這難不倒我的、訊號驅動的是非同步的,其他的都是同步的。
錯錯錯,上面的所有的都是同步的。
為什麼以上四種都是同步的
我們說阻塞IO模型、非阻塞IO模型、IO複用模型和訊號驅動IO模型都是同步的IO模型。原因是因為,無論以上那種模型,真正的資料拷貝過程,都是同步進行的。
訊號驅動難道不是非同步的麼? 訊號驅動,核心是在資料準備好之後通知程式,然後程式再通過recvfrom
操作進行資料拷貝。我們可以認為資料準備階段是非同步的,但是,資料拷貝操作是同步的。所以,整個IO過程也不能認為是非同步的。
你呦把我繞懵了,你還是拿釣魚來說吧。
好的。
我們把釣魚過程,可以拆分為兩個步驟:1、魚咬鉤(資料準備)。2、把魚釣起來放進魚簍裡(資料拷貝)。無論以上提到的哪種釣魚方式,在第二步,都是需要人主動去做的,並不是魚竿自己完成的。所以,這個釣魚過程其實還是同步進行的。
這和燒水有啥區別,你不是告訴我安裝報警器的水壺是非同步的嗎?
同樣是報警器,燒水和釣魚的是兩回事。
燒水的報警器一響,整個燒水過程就完成了。水已經是開水了。
釣魚的報警器一響,只能說明魚兒已經咬鉤了,但是還沒有真正的釣上來。
所以 ,使用帶有報警器的水壺燒水,燒水過程是非同步的。
而使用帶有報警器的魚竿釣魚,釣魚的過程還是同步的。
這次我明白了,那有沒有真正非同步的IO呢?
其實是有的。
非同步IO模型
我們釣魚的時候,採用一種高科技釣魚竿,即全自動釣魚竿。可以自動感應魚上鉤,自動收竿,更厲害的可以自動把魚放進魚簍裡。然後,通知我們魚已經釣到了,他就繼續去釣下一條魚去了。
對映到Linux作業系統中,這就是非同步IO模型。應用程式把IO請求傳給核心後,完全由核心去操作檔案拷貝。核心完成相關操作後,會發訊號告訴應用程式本次IO已經完成。
使用者程式發起aio_read
操作之後,給核心傳遞描述符、緩衝區指標、緩衝區大小等,告訴核心當整個操作完成時,如何通知程式,然後就立刻去做其他事情了。當核心收到aio_read
後,會立刻返回,然後核心開始等待資料準備,資料準備好以後,直接把資料拷貝到使用者控制元件,然後再通知程式本次IO已經完成。
這種方式的釣魚,無疑是最省事兒的。啥都不需要管,只需要交給魚竿就可以了。
嗯,這次我明白了,原來這才叫非同步的IO。
是的,以上就是Linux作業系統的5種IO模型啦。
5種IO模型對比
看來這個問題確實挺難的。這個小朋友沒回答上來也算可以理解了吧。
這個問題看似複雜,但其實是看一個人是否真正理解IO的最好的問題了。
行行行,你說的都對。
額
介紹完這些之後,我默默的刪掉了之前寫好的那句面試評價『對Linux的基本IO模型理解不深』,改成了『對IO體系理解的不夠深入,只會使用封裝好的API』。
(完)
Java團長
專注於Java乾貨分享
掃描上方二維碼獲取更多Java乾貨
相關文章
- 漫話:如何給女朋友解釋什麼是Linux的五種IO模型?Linux模型
- 如何給女朋友解釋什麼是RPCRPC
- 如何給女朋友解釋什麼是IO中的阻塞、非阻塞、同步、非同步?非同步
- 漫話:如何給女朋友解釋什麼是HTTPHTTP
- 漫話:如何給女朋友解釋什麼是反向代理?
- 漫話:如何給女朋友解釋什麼是策略模式?模式
- 圖文詳解:如何給女朋友解釋什麼是微服務?微服務
- 漫話:如何給女朋友解釋什麼是Git和GitHub?Github
- 漫話:如何給女朋友解釋什麼是單例模式?單例模式
- 如何給女朋友解釋什麼是併發和並行並行
- 如何給女朋友解釋什麼是分散式和叢集?分散式
- 漫話:如何給女朋友解釋什麼是系統可用性?
- 漫話:如何給女朋友解釋什麼是分散式和叢集?分散式
- 漫話:如何給女朋友解釋什麼是併發和並行並行
- 【IO】Linux下的五種IO模型Linux模型
- 給女朋友講解什麼是代理模式模式
- Linux 下的五種 IO 模型Linux模型
- 給女朋友講解什麼是Optional【JDK 8特性】JDK
- 漫話:給女朋友解釋GC如何判斷什麼東西可以回收?GC
- (四)五種IO模型模型
- 五種網路io模型模型
- 五種傳統IO模型模型
- 漫話:如何給女朋友解釋為什麼有些網站域名不以www開頭網站
- 漫話:如何給女朋友解釋為什麼雙11無法修改收貨地址
- 怎麼向女朋友解釋什麼叫區塊鏈?區塊鏈
- 圖解四種 IO 模型圖解模型
- 五種IO模型介紹和對比模型
- 漫話:如何給女朋友解釋為什麼Windows上面的軟體都想把自己安裝在C盤Windows
- 用通俗易懂的方式講IO的五種模型模型
- 漫話:給女朋友解釋為什麼隨機播放歌曲並不隨機隨機
- Linux 的 Socket IO 模型趣解Linux模型
- 【網路IO系列】IO的五種模型,BIO、NIO、AIO、IO多路複用、 訊號驅動IO模型AI
- 如何用Java與python程式碼解釋IO模型JavaPython模型
- 給女朋友講ActiveMQ是啥?MQ
- 幽默講解 Linux 的 Socket IO 模型Linux模型
- 漫話:如何給女朋友解釋為什麼12306會使用者資訊洩露(上)——密碼篇密碼
- linux的IO模型Linux模型
- 通過程式碼解釋什麼是API,什麼是SDK?API