Linux 五種I/O技術(shù)以及在Java中應(yīng)用

Linux 五種I/O技術(shù)以及在Java中應(yīng)用

I/O概念說明

在學(xué)習(xí)linux內(nèi)核I/O方面的知識,首先要了解一下概念。

用戶空間和內(nèi)核空間

  • 內(nèi)核空間:操作系統(tǒng)的核心是內(nèi)核,可以訪問受保護(hù)的內(nèi)存空間、硬件設(shè)備、執(zhí)行高權(quán)限指令。內(nèi)核由系統(tǒng)中所有進(jìn)程共享,當(dāng)進(jìn)程運(yùn)行在內(nèi)核空間時屬于內(nèi)核態(tài)。當(dāng)程序執(zhí)行了系統(tǒng)調(diào)用(例如:磁盤io)或者觸發(fā)異常中斷,此時進(jìn)程就會進(jìn)入內(nèi)核態(tài)。
  • 用戶空間:存放用戶程序的代碼和數(shù)據(jù),執(zhí)行l(wèi)inux第三級別的指令。運(yùn)行在用戶空間的進(jìn)程處于用戶態(tài)。
  • 上下文切換:用戶應(yīng)用空間的進(jìn)程通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核態(tài)時,需要傳遞用戶空間的很多變量、參數(shù)等信息給內(nèi)核。內(nèi)核態(tài)運(yùn)行時也會保存進(jìn)程的寄存器值和變量信息,在用戶進(jìn)程恢復(fù)時傳遞該數(shù)據(jù)給用戶態(tài)。

進(jìn)程切換

操作系統(tǒng)為運(yùn)行的每個進(jìn)程開辟一個進(jìn)程表項,該項包含了進(jìn)程狀態(tài)、程序計數(shù)器、堆棧指針、內(nèi)存分配、打開文件描述等上下文信息。進(jìn)程的切換是內(nèi)核掛起正在執(zhí)行的進(jìn)程,并恢復(fù)以前運(yùn)行的進(jìn)程的過程。

進(jìn)程阻塞

正在執(zhí)行的進(jìn)程,由于需要請求系統(tǒng)資源或者等待某種操作完成,而主動執(zhí)行阻塞令名 使 進(jìn)程進(jìn)入阻塞狀態(tài)。進(jìn)入阻塞狀態(tài)后,進(jìn)程是不占有cpu資源的。

文件描述符

它是一個用于表述指向文件的引用的抽象化概念。指向內(nèi)核維護(hù)的進(jìn)程打開文件的記錄表。

I/O緩存

在linux操作系統(tǒng)會將 IO 的數(shù)據(jù)緩存在文件系統(tǒng)的頁緩存,磁盤數(shù)據(jù)會先被寫入到內(nèi)核系統(tǒng)緩沖區(qū),然后操作系統(tǒng)內(nèi)核將緩沖區(qū)數(shù)據(jù)復(fù)制到應(yīng)用程序地址空間。數(shù)據(jù)會在內(nèi)核空間和用戶空間之間進(jìn)行多次拷貝。為解決socket用戶空間和內(nèi)核空間之間的數(shù)據(jù)拷貝問題,一般采用zero-copy技術(shù)解決。例如java中FileChannel.transferTo(long position, long count, WritableByteChannel target)將數(shù)據(jù)從文件通道傳輸?shù)搅私o定的可寫字節(jié)通道。

Linux IO模型

在Linux 系統(tǒng)中常用的IO模型有阻塞BIO、非阻塞NIO、IO多路復(fù)用epoll、異步模式AIO。其中阻塞、非阻塞、多路復(fù)用都是同步模型。

IO涉及兩個階段:
第一階段:等待數(shù)據(jù)準(zhǔn)備 (Waiting for the data to be ready)。
第二階段:將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程中 (Copying the data from the kernel to the process)。

同步阻塞模型BIO

在同步阻塞模型中,通過調(diào)用操作系統(tǒng)命令recvform 阻塞應(yīng)用程序,同步阻塞等待數(shù)據(jù)從內(nèi)核態(tài)復(fù)制到用戶態(tài)。在等待數(shù)據(jù)處理的兩個階段,整個進(jìn)程都是阻塞的。


image.png

流程描述:
進(jìn)程調(diào)用了recv()/recvfrom()這個系統(tǒng)調(diào)用,內(nèi)核kernel 執(zhí)行第一階段數(shù)據(jù)準(zhǔn)備,kernel阻塞等待數(shù)據(jù)到來。等內(nèi)核態(tài)數(shù)據(jù)緩存區(qū)準(zhǔn)備好數(shù)據(jù)后,會進(jìn)行第二個階段。將數(shù)據(jù)從內(nèi)核kernel緩存區(qū)拷貝到用戶空間(拷貝階段同步阻塞)。

同步非阻塞模型NIO

同步非阻塞模型的原理是通過輪詢的方式,判斷kernel內(nèi)核是否數(shù)據(jù)準(zhǔn)備完成。非阻塞將大的整片時間的阻塞分成N多的小的阻塞。操作系統(tǒng)調(diào)用recvform命令后,進(jìn)程并不阻塞而是立即返回進(jìn)程,然后循環(huán)往復(fù)的進(jìn)行recvform系統(tǒng)調(diào)用。輪詢檢測內(nèi)核數(shù)據(jù)狀態(tài),直到內(nèi)核緩存數(shù)據(jù)準(zhǔn)備完成,再進(jìn)行數(shù)據(jù)拷貝。

image.png

該模型會導(dǎo)致系統(tǒng)吞吐量下降,因為每個一段時間輪詢一次,而內(nèi)核數(shù)據(jù)準(zhǔn)備完成時間是任意的。

多路復(fù)用I/O模型

多路復(fù)用模型是通過操作系統(tǒng)底層調(diào)用select、poll、epoll函數(shù)命令。在select()函數(shù)處阻塞 監(jiān)聽 多個IO端口,當(dāng)任何一個socket內(nèi)核數(shù)據(jù)準(zhǔn)備好時返回,然后調(diào)用recvform命令將數(shù)據(jù)從內(nèi)核態(tài)拷貝到用戶態(tài)。多路復(fù)用模型select()也會阻塞進(jìn)程,而與阻塞模型不同的是 該 函數(shù)可以阻塞多個socket。

image.png

IO多路復(fù)用是阻塞在select,epoll這樣的系統(tǒng)調(diào)用之上,而沒有阻塞在真正的I/O系統(tǒng)調(diào)用如recvfrom之上。從而使在單線程情況下可以操作多個客戶端請求。

IO多路復(fù)用模型最大優(yōu)勢是不需要創(chuàng)建的額外的線程 系統(tǒng)開銷小,節(jié)省系統(tǒng)資源。其底層實現(xiàn)方式是操作系統(tǒng)命令支持,select、poll、epoll函數(shù)命令。

異步非阻塞模型AIO

Linux提供了AIO庫函數(shù)實現(xiàn)異步,當(dāng)用戶發(fā)起aio_read操作后 內(nèi)核 會立即返回不會block。內(nèi)核會負(fù)責(zé)數(shù)據(jù)準(zhǔn)備和數(shù)據(jù)從內(nèi)核態(tài)拷貝到用戶態(tài),完成之后會向用戶進(jìn)程發(fā)送signal或通過線程回調(diào)函數(shù)完成IO 處理過程。

image.png

在non-blocking IO中,雖然進(jìn)程大部分時間都不會被block,但是它仍然要求進(jìn)程去主動的check,并且當(dāng)數(shù)據(jù)準(zhǔn)備完成以后,也需要進(jìn)程主動的再次調(diào)用recvfrom來將數(shù)據(jù)拷貝到用戶內(nèi)存。而asynchronous IO則完全不同。它就像是用戶進(jìn)程將整個IO操作交給了他人(kernel)完成,然后他人做完后發(fā)信號通知。在此期間,用戶進(jìn)程不需要去檢查IO操作的狀態(tài),也不需要主動的去拷貝數(shù)據(jù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容