【IO】Linux下的五種IO模型
Linux 提供了五種 IO 模型,包括:阻塞IO、非阻塞IO、IO多路複用、訊號驅動IO、非同步IO。
當使用者程式請求I/O操作,發起對socket套接字的讀操作時,該使用者程式會執行一個系統呼叫,將本程式的控制權移交給核心。在unix作業系統中,一個IO操作主要經過兩個階段:
- 等待資料準備;等資料流到來後,會將它從網路卡複製到核心空間的緩衝區(階段一)
- 將資料從核心空間拷貝到使用者程式中;將資料從核心緩衝區向使用者程式緩衝區複製(階段二)
PS:當程式執行在核心態時,會產生上下文切換,並且在應用程式看來,其自身使用者程式此時是阻塞等待的
1.阻塞 IO 模型
Linux作業系統中,這就是一種最簡單的IO模型,即阻塞IO。一般表現為程式或執行緒等待某個條件,如果條件不滿足,則一直等下去。條件滿足,則進行下一步操作。
當使用者執行緒發出 IO 請求之後,核心會去檢視資料是否就緒,如果沒有就緒就會等待資料就緒,而使用者執行緒就會處於阻塞狀態,使用者執行緒交出 CPU。當資料就緒之後,核心會將資料拷貝到使用者執行緒,並返回結果給使用者執行緒,使用者執行緒才解除 block 狀態。
典型的阻塞 IO 模型的例子為:
data = socket.read();
如果資料沒有就緒,就會一直阻塞在 read 方法。
recvfrom
是 Linux 系統提供給使用者用於接收網路IO的系統介面,作用是從套接字上接收一個訊息。ssize_t recvfrom(int sockfd,void *buf,size_t len,unsigned int flags, struct sockaddr *from,socket_t *fromlen);
- 成功執行時,返回接收到的位元組數
- 另一端已關閉時,返回0
- 失敗返回-1,errno被設為以下的某個值
- EAGAIN:套接字已標記為非阻塞,而接收操作被阻塞或者接收超時
- EBADF:sock不是有效的描述詞
- ECONNREFUSE:遠端主機阻絕網路連線
- EFAULT:記憶體空間訪問出錯
- EINTR:操作被訊號中斷
- EINVAL:引數無效
- ENOMEM:記憶體不足
- ENOTCONN:與面向連線關聯的套接字尚未被連線上
- ENOTSOCK:sock索引的不是套接字
recvfrom 很關鍵,因為前4種IO模型都設計此係統呼叫。
2.非阻塞 IO 模型
當使用者執行緒發起一個 read 操作後,並不需要等待,而是馬上就得到了一個結果。如果結果是一個 error 時,它就知道資料還沒有準備好,於是它可以再次傳送 read 操作。一旦核心中的資料準備好了,並且又再次收到了使用者執行緒的請求,那麼它馬上就將資料拷貝到了使用者執行緒,然後返回。
所以事實上,在非阻塞 IO 模型中,使用者執行緒需要不斷地詢問核心資料是否就緒,也就說非阻塞 IO 不會交出 CPU,而會一直佔用 CPU。
典型的非阻塞 IO 模型一般如下:
while(true){
data = socket.read();
if(data!= error){
process(data);
break;
}
}
但是對於非阻塞 IO 就有一個非常嚴重的問題,在 while 迴圈中需要不斷地去詢問核心資料是否就緒,這樣會導致 CPU 佔用率非常高,因此一般情況下很少使用 while 迴圈這種方式來讀取資料。
3.多路複用 IO 模型
多路複用 IO 模型是目前使用得比較多的模型。Java NIO 實際上就是多路複用 IO。
在多路複用 IO 模型中,會有一個執行緒不斷去輪詢多個 socket 的狀態,只有當 socket 真正有讀寫事件時,才真正呼叫實際的 IO 讀寫操作。因為在多路複用 IO 模型中,只需要使用一個執行緒就可以管理多個 socket,系統不需要建立新的程式或者執行緒,也不必維護這些執行緒和程式,並且只有在真正有 socket 讀寫事件進行時,才會使用 IO 資源,所以它大大減少了資源佔用。
在 Java NIO 中,是通過 selector.select ()
去查詢每個通道是否有到達事件,如果沒有事件,則一直阻塞在那裡,因此這種方式會導致使用者執行緒的阻塞。
也許有朋友會說,我可以採用多執行緒 + 阻塞 IO 達到類似的效果,但是由於在多執行緒 + 阻塞 IO 中,每個 socket 對應一個執行緒,這樣會造成很大的資源佔用,並且尤其是對於長連線來說,執行緒的資源一直不會釋放,如果後面陸續有很多連線的話,就會造成效能上的瓶頸。
而多路複用 IO 模式,通過一個執行緒就可以管理多個 socket,只有當 socket 真正有讀寫事件發生才會佔用資源來進行實際的讀寫操作。因此,多路複用 IO 比較適合連線數比較多的情況。
另外多路複用 IO 為何比非阻塞 IO 模型的效率高是因為在非阻塞 IO 中,不斷地詢問 socket 狀態時通過使用者執行緒去進行的,而在多路複用 IO 中,輪詢每個 socket 狀態是核心在進行的,這個效率要比使用者執行緒要高的多。
不過要注意的是,多路複用 IO 模型是通過輪詢的方式來檢測是否有事件到達,並且對到達的事件逐一進行響應。因此對於多路複用 IO 模型來說,一旦事件響應體很大,那麼就會導致後續的事件遲遲得不到處理,並且會影響新的事件輪詢。
4.訊號驅動 IO 模型
在訊號驅動 IO 模型中,當使用者執行緒發起一個 IO 請求操作,會給對應的 socket 註冊一個訊號函式,然後使用者執行緒會繼續執行,當核心資料就緒時會傳送一個訊號給使用者執行緒,使用者執行緒接收到訊號之後,便在訊號函式中呼叫 IO 讀寫操作來進行實際的 IO 請求操作。這個一般用於 UDP 中,對 TCP 套介面幾乎是沒用的,原因是該訊號產生得過於頻繁,並且該訊號的出現並沒有告訴我們發生了什麼事情
5.非同步 IO 模型
非同步 IO 模型才是最理想的 IO 模型,在非同步 IO 模型中,當使用者執行緒發起 read 操作之後,立刻就可以開始去做其它的事。而另一方面,從核心的角度,當它受到一個 asynchronous read 之後,它會立刻返回,說明 read 請求已經成功發起了,因此不會對使用者執行緒產生任何 block。然後,核心會等待資料準備完成,然後將資料拷貝到使用者執行緒,當這一切都完成之後,核心會給使用者執行緒傳送一個訊號,告訴它 read 操作完成了。也就說使用者執行緒完全不需要關心實際的整個 IO 操作是如何進行的,只需要先發起一個請求,當接收核心返回的成功訊號時表示 IO 操作已經完成,可以直接去使用資料了。
也就說在非同步 IO 模型中,IO 操作的兩個階段都不會阻塞使用者執行緒,這兩個階段都是由核心自動完成,然後傳送一個訊號告知使用者執行緒操作已完成。使用者執行緒中不需要再次呼叫 IO 函式進行具體的讀寫。這點是和訊號驅動模型有所不同的,在訊號驅動模型中,當使用者執行緒接收到訊號表示資料已經就緒,然後需要使用者執行緒呼叫 IO 函式進行實際的讀寫操作;而在非同步 IO 模型中,收到訊號表示 IO 操作已經完成,不需要再在使用者執行緒中呼叫 iO 函式進行實際的讀寫操作。
注意,非同步 IO 是需要作業系統的底層支援,在 Java 7 中,提供了 Asynchronous IO。簡稱 AIO
小結
將這五種 IO 模型放到一起對比一下:
前面四種 IO 模型實際上都屬於同步 IO,只有最後一種是真正的非同步 IO,因為無論是多路複用 IO 還是訊號驅動模型,IO 操作的第 2 個階段都會引起使用者執行緒阻塞,也就是核心進行資料拷貝的過程都會讓使用者執行緒阻塞。
相關文章
- (四)五種IO模型模型
- 五種網路io模型模型
- 五種傳統IO模型模型
- 【網路IO系列】IO的五種模型,BIO、NIO、AIO、IO多路複用、 訊號驅動IO模型AI
- linux的IO模型Linux模型
- 五種IO模型介紹和對比模型
- 如何給女朋友解釋什麼是Linux的五種IO模型?Linux模型
- 用通俗易懂的方式講IO的五種模型模型
- 漫話:如何給女朋友解釋什麼是Linux的五種IO模型?Linux模型
- Linux中的IO模型介紹Linux模型
- 圖解四種 IO 模型圖解模型
- 一頓飯的事兒,搞懂Linux5種IO模型Linux模型
- 【OS】5種網路IO模型模型
- IO模型模型
- IO模型學習(一)IO模型分類模型
- 今天我們來聊Java IO模型,BIO、NIO、AIO三種常見IO模型Java模型AI
- io模型 WSAAsyncSelect模型
- 從作業系統層面理解Linux下的網路IO模型作業系統Linux模型
- IO通訊模型(三)多路複用IO模型
- Linux網路程式設計之IO模型Linux程式設計模型
- 圖解Linux的IO模型和相關技術圖解Linux模型
- Java3種IO模型,一次搞懂!Java模型
- 【NIO系列】——之IO模型模型
- WinSock 重疊IO模型模型
- IO通訊模型(二)同步非阻塞模式NIO(NonBlocking IO)模型模式BloC
- RPC設計應該使用哪種網路IO模型?RPC模型
- NIO(二)淺析IO模型模型
- Linux IO排程方法Linux
- 簡述Linux磁碟IOLinux
- Linux C 檔案IOLinux
- Linux檔案IO操作Linux
- 通過IO模型帶來的思考模型
- IO模型與吃飯的那些事模型
- 框架篇:見識一下linux高效能網路IO+Reactor模型框架LinuxReact模型
- IO模式和IO多路複用(阻塞IO、非阻塞IO、同步IO、非同步IO等概念)模式非同步
- Linux程式設計學習筆記 | Linux IO學習[2] – 標準IOLinux程式設計筆記
- Linux裡五種I/O模型Linux模型
- 談談對不同I/O模型的理解 (阻塞/非阻塞IO,同步/非同步IO)模型非同步