java中的io复用_从 Java 中的零拷贝到五种IO模型
在之前的文章中,我們聊過了 Java 中的零拷貝,零拷貝就是指數據不會在內核空間和用戶空間之間相互拷貝。這樣就減少了內核態與用戶態的切換,自然就很高效。
拷貝文件只是 IO 操作中一個特殊的情況,大多數的 IO 操作還是需要將數據從內核空間移到用戶空間,這往往是一個比較耗時的操作。
IO 操作不僅僅指對文件的讀寫,網絡的通信同樣也是 IO 操作。
如今很多系統的瓶頸就在于 IO 上,比如經典的 C10K,C10M 問題本質上就是在解決 IO 問題。
這篇文章將介紹經典的 IO 模型的實現原理,以及說明 Java IO 與這幾種 IO 模型的關系。
💡本文討論的環境為 Linux
IO 操作是怎么實現的
IO 操作是一個很復雜的過程,遠遠不止調用一個函數那么簡單,因為每一次的 IO 操作都會涉及到操作系統的內核空間和用戶空間的轉換,真正執行的 IO 操作實際上是在操作系統的內核空間進行。
這是一個很耗資源的操作。計算機中內存和 CPU 都是非常稀有的資源,應該盡可能提高這些資源的使用效率。
IO 操作經常需要與磁盤就行交互,所以IO 操作相比于 CPU 的速度要慢好幾個數量級。利用這兩者之間的速度差異,就可以實現不同種類的 IO 方式,也就是俗稱的 IO 模型。
當然,這些 IO 操作的都在操作系統層面上實現好了,編程語言可以利用這些能力去實現 IO 相關的 API。
五種 IO 模型
在 操作系統中,IO 模型有如下五種:
在上文已經說到,其實 IO 操作就是將數據在用戶空間與內核空間進行相互轉換,這個過程是通過系統調用來完成的。 IO 技術的發展目標就是如何使用盡可能少的資源來完成數據的傳輸,這里資源主要就是指 CPU 資源。
無論是文件 IO,還是網絡 IO,最后都可以統一為用戶空間和內核空間數據的交換。
BIO
BIO 是最經典的一種 IO 方式,也是最簡單粗暴的方式,在發起 IO 操作之后,當前調用線程就會處在阻塞狀態,直到數據傳輸完成。
NIO
NIO 是在 BIO 基礎之上的一個改進,NIO 在數據還未準備好的情況下,不會阻塞進程,而是通過輪詢的方式,不斷的去查詢數據時候準備好,當數據可以被讀取時,當前線程就會處在阻塞狀態,直到數據讀取完成。
所以 NIO 中的非阻塞指的是在等待數據的階段,實際進行數據傳輸時,還是阻塞的,這點需要注意。
IO 多路復用
IO 多路復用是對 NIO 的一個改進,在 NIO 中,需要不斷輪詢查看數據是否準備好,IO 多路復用的改進是不再主動去查詢數據狀態是否準備完成,而是等數據準備好的通知,當數據準備完成之后,才會開始傳輸數據。
與 NIO 一樣,在數據的傳輸階段,當前線程依然是阻塞的。
在 Linux 系統中,IO 多路復用的方式有多種:
select
poll
epoll
信號驅動 IO
信號驅動 IO 通過 sigaction 系統調用,向內核發送一個信號,當內核中數據準備好之后,當前線程也會接收到一個信號,在這個過程中,當前線程也是非阻塞的。在接收到信號之后,就可以開始傳輸數據。
AIO
上面的這些 IO 模型雖然有些號稱是不阻塞的,那是指在等待數據就緒的過程中是不阻塞的,但是在接收數據的時候,依然還是阻塞的。
AIO 是這些 IO 模型中真正實現完全不阻塞,AIO 在被調用之后直接返回,連接收數據的階段也是非阻塞的,等到數據接收完成之后,內核才會返回一個通知,也就是說當用戶進程接收到通知時,數據已經接收完成。
在 Linux 中提供了 AIO 的實現,但是實際上使用的并不多,更多還是使用獨立的異步 IO 庫,比如libevent、libev、libuv。
五種 IO 模式的總結如下:
Java 中 IO 的實現
Java 中的 IO 也不例外,實際的 IO 是調用了系統的能力來完成,在用戶態通過系統調轉到內核態,最終實現文件的讀寫或者通信。
Java 中 IO 就是典型的 BIO,而且 NIO 則不是對應五種 IO 模型中的 NIO,Java 中的 NIO 實際上是使用 IO 多路復用來實現的。
Java 中的 NIO2 也稱之為 AIO,正是對應操作系統中的 AIO,當然具體的實現可能是其他的庫。
文 / Rayjun
REF
[1] Unix 網絡編程
總結
以上是生活随笔為你收集整理的java中的io复用_从 Java 中的零拷贝到五种IO模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java plug机制_【maven实战
- 下一篇: java oo 封装_Java从小白到入