日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
對IO概念模糊:計算機IO過程與零拷貝

一、前置知識

1.1 內(nèi)存分段

現(xiàn)代計算機在加載操作系統(tǒng)、正常啟動后,其內(nèi)存會主要分成兩大段:

創(chuàng)新互聯(lián)是一家專注于網(wǎng)站制作、成都做網(wǎng)站與策劃設(shè)計,站前網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十多年,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:站前等地區(qū)。站前做網(wǎng)站價格咨詢:13518219792

  • 內(nèi)核段
  • 用戶段

內(nèi)核段:

操作系統(tǒng)本質(zhì)上是一個計算機的管理程序,該程序相關(guān)的所有資源,被存放在內(nèi)核段中。

用戶段:

用戶段用來存放各個進程的數(shù)據(jù)和指令。

根據(jù)所訪問的內(nèi)存段的不同,CPU會處于不同的態(tài),訪問用戶段的時候處于用戶態(tài),訪問內(nèi)核段的時候處于內(nèi)核態(tài)。

1.2 CPU的態(tài)

1.2.1 CPU的工作過程

CPU要執(zhí)行的指令的地址存在寄存器中,指令存放在內(nèi)存中,而CPU本質(zhì)上就是一個去內(nèi)存中根據(jù)地址取指令,然后執(zhí)行指令的硬件。

舉一個例子:

例如PC寄存器中存放50,CPU讀到存放的50,發(fā)出一條取址指令,去取出地址為50的內(nèi)存單元中的指令,再傳回給CPU。

1.2.2 寄存器

眾所周知,為了配平CPU和內(nèi)存之間速率的差距,CPU和內(nèi)存之間存在著一個由寄存器組成的中間層,寄存器種會存放著CPU接下來要執(zhí)行的指令,以及后續(xù)可能要執(zhí)行到的指令以及可能要用到的數(shù)據(jù)。只有預(yù)先裝載進去這部分可能要用到的東西才能抹平CPU和內(nèi)存之間的速率差距,不然每次都要去內(nèi)存取內(nèi)容,可能是會拉低CPU的效率的。

但該預(yù)先裝載哪些內(nèi)容進寄存器中呢?這里遵循了程序的局部性原理。

程序的局部性原理:

程序在執(zhí)行的時候呈現(xiàn)出局部性規(guī)律,在一段時間內(nèi),整個程序的執(zhí)行僅限于程序中的某一個部分,相應(yīng)的,執(zhí)行所訪問的存儲空間也局限于某個內(nèi)存區(qū)域。局部性又分為時間局部性和空間局部性。時間局部性指的是,如果程序中的某條指令一旦執(zhí)行,則不久后可能會被再次執(zhí)行,執(zhí)行指令時訪問的數(shù)據(jù)單元在不久后會被再次訪問??臻g局部性指的是,一旦訪問了某個存儲單元,不久后,其附近的存儲單元也將被訪問。

1.2.3 CPU的上下文

為了抹平內(nèi)存和CPU之間的速率差,給CPU配備了寄存器。寄存器中存儲著當前執(zhí)行的指令、數(shù)據(jù)、以及下一條指令在內(nèi)存中的地址等等事關(guān)程序正常運行的關(guān)鍵信息。所以寄存器中存儲的內(nèi)容合稱為CPU的上下文。

1.2.4 系統(tǒng)調(diào)用

系統(tǒng)中將一些對系統(tǒng)級別資源的調(diào)用封裝成了一個個函數(shù),稱為系統(tǒng)調(diào)用,常見的系統(tǒng)調(diào)用有很多,比如IO操作就是個系統(tǒng)調(diào)用。

1.2.5 CPU的態(tài)

操作系統(tǒng)在啟動后,內(nèi)存被分為兩部分(兩段):

  • 內(nèi)核段從0地址開始編址,存放操作系統(tǒng)程序,里面包含系統(tǒng)調(diào)用。
  • 用戶段,從內(nèi)核段之后開始編址,存放用戶程,也就是各個進程的數(shù)據(jù)和指令。

由于內(nèi)核段存放的是系統(tǒng)相關(guān)的內(nèi)容,基于安全的考慮,肯定是不允許被CPU隨意訪問的,需要特權(quán)才行。因此將CPU的權(quán)限設(shè)計為了兩種狀態(tài):

  • 用戶態(tài),只能訪問用戶段
  • 內(nèi)核態(tài),能訪問用戶段和內(nèi)核段

所謂的態(tài)就是能訪問用戶段的上下文以及能訪問內(nèi)核段的上下文。當我們調(diào)用系統(tǒng)調(diào)用的時候會引起上下文的切換,也就是CPU態(tài)的切換。上下文切換的意思是,先把前一個任務(wù)的 CPU 上下文保存起來,然后加載新任務(wù)的上下文到這些寄存器和程序計數(shù)器,最后再跳轉(zhuǎn)到程序計數(shù)器所指的新位置,運行新任務(wù)。之所以會切換上下文,這是因為寄存器加載數(shù)據(jù)和指令的時候遵循了程序的局部性原理。CPU訪問用戶段時,寄存器里預(yù)加載的是用戶段的資源;CPU訪問內(nèi)核段時,寄存器里預(yù)加載的是內(nèi)核段的資源。

所以CPU進行態(tài)切換的時候,上下文一定會完全換一套的。總的來說為了保證多數(shù)情況下程序執(zhí)行的效率,“局部性原理”是必須存在的,為了內(nèi)核的安全,CPU態(tài)的劃分是必須存在的。所以,CPU上下文切換是不得不接受的一種代價。

CPU的上下文切換是種耗時的操作:

寄存器保存和恢復(fù):在上下文切換過程中,需要保存當前任務(wù)的寄存器狀態(tài),并恢復(fù)下一個任務(wù)的寄存器狀態(tài)。寄存器保存和恢復(fù)涉及將寄存器的值從CPU保存到內(nèi)存(或者棧)中,以及從內(nèi)存中恢復(fù)到CPU中。這涉及到數(shù)據(jù)的讀寫和復(fù)制操作,會引入一定的延遲和開銷。

內(nèi)存刷新和緩存失效:上下文切換可能涉及刷新CPU緩存和內(nèi)存管理單元(MMU)的操作。當切換到一個新的任務(wù)時,之前的任務(wù)的緩存內(nèi)容可能需要刷新,新任務(wù)的頁表和內(nèi)存映射需要加載和設(shè)置,這些操作可能導(dǎo)致緩存失效和內(nèi)存訪問延遲。

上下文數(shù)據(jù)復(fù)制:在上下文切換過程中,需要將當前任務(wù)的上下文數(shù)據(jù)保存到內(nèi)存中,同時從內(nèi)存中加載下一個任務(wù)的上下文數(shù)據(jù)。這包括寄存器狀態(tài)、程序計數(shù)器、標志位和其他與任務(wù)執(zhí)行相關(guān)的數(shù)據(jù)。數(shù)據(jù)的復(fù)制和加載需要占用CPU和內(nèi)存帶寬,并引入一定的延遲。

任務(wù)切換開銷:上下文切換不僅僅涉及寄存器和內(nèi)存的操作,還包括任務(wù)切換本身的開銷。這包括切換內(nèi)核棧、更新任務(wù)控制塊(TCB)、更新調(diào)度器數(shù)據(jù)結(jié)構(gòu)等操作。這些操作可能需要修改內(nèi)核數(shù)據(jù)結(jié)構(gòu),增加了上下文切換的開銷。

總的來說CPU上下文切換很耗時,我們常見的就是IO操作、進程切換這些都會引起CPU上下文切換。

1.3 計算機IO的過程

在程序執(zhí)行時有很多高耗時操作,比如IO操作就是。當計算機執(zhí)行IO操作的時候,IO設(shè)備的速度肯定是遠遠落后于CPU的速度的,IO沒有完成,后續(xù)依賴的數(shù)據(jù)沒到位,程序也沒辦法繼續(xù)向下執(zhí)行,于是CPU就只好賦閑,傻傻的等IO執(zhí)行完成,再繼續(xù)向下運行程序,無疑這會造成CPU資源的浪費,使得計算機的工作效率變得很低。

于是現(xiàn)代操作系統(tǒng)中將CPU劃分成了很多時間片,不同時間片可以去運行不同的程序,比如:

  1. 這一秒運行的A程序,
  2. 下一秒運行的B程序,
  3. 再下一秒再運行A程序。

這樣間插執(zhí)行就會避免傻等帶來的CPU資源的浪費,如果IO耗時2秒,那么CPU至少還有1秒被其它程序使用到了。

后來操作系統(tǒng)用了更激進的方式來處理IO指令,讓CPU的時間一絲一毫都不被浪費,這種處理方式就是遇見IO指令,直接啟動IO后,CPU直接轉(zhuǎn)去執(zhí)行其它任務(wù),當IO完成后發(fā)送一個中斷信號給CPU,讓CPU中斷當前的任務(wù),轉(zhuǎn)過來繼續(xù)執(zhí)行IO后的程序

1.4 IO與內(nèi)存

計算機進行IO的時候,本質(zhì)上會為每一個IO設(shè)備在內(nèi)存中分配一塊空間,向這塊空間里進行讀寫,即可完成IO。為什么給IO設(shè)備分配的內(nèi)存會是在內(nèi)核段里喃?主要是基于兩點進行考慮的:

  • 安全性
  • 特權(quán)操作

1.4.1 安全性:

I/O 操作通常需要與計算機的外部設(shè)備(如磁盤、網(wǎng)絡(luò)設(shè)備等)進行交互,如果允許各個進程自己私自與外部設(shè)備進行交互,IO的內(nèi)存放在各個進程內(nèi)部,太散了,不是很好進行安全控制,相反,如果將IO的內(nèi)存放在內(nèi)核段,就很便于集中管理,可以附加一些安全機制上去。

1.4.2 特權(quán)操作:

首先IO指令本身就是特權(quán)指令,會讓CPU進入內(nèi)核態(tài),其次進行IO的時候會用到中斷信號,也涉及到特權(quán)指令,也要求CPU處于內(nèi)核態(tài),所以如果IO內(nèi)存是在內(nèi)核段中,讓CPU提前進入內(nèi)核狀態(tài),也避免了后面來回切狀態(tài)造成的時間浪費。

整個IO在內(nèi)存中的流轉(zhuǎn)過程如下:

讀的時候磁盤拷貝到內(nèi)核段、內(nèi)核段拷貝到用戶段,

寫的時候用戶段拷貝到內(nèi)核段、內(nèi)核段拷貝到磁盤。

一共四次復(fù)制。

特別說明:

我知道其它很多地方這里將圖畫成了這個樣子:

這是因為他描繪的這次IO是從磁盤上讀出來然后寫到網(wǎng)絡(luò)上去,網(wǎng)卡和磁盤可以理解為兩個不同的IO設(shè)備,所以他們在內(nèi)核段中的IO內(nèi)存,地址是不同的。但是如果僅僅是對磁盤的一次本地IO,那么進行IO的內(nèi)核段地址會是同一個,在同一個地址內(nèi)進行讀寫。這里為了涵蓋多種情況,所以博主沒有將它分開,讀者悉知。

二、零拷貝

零拷貝(Zero-copy)是一種優(yōu)化技術(shù),并不是一次拷貝都不做,而是旨在減少數(shù)據(jù)在系統(tǒng)內(nèi)部的復(fù)制操作,從而提高數(shù)據(jù)傳輸?shù)男?。它的主要目標是減少內(nèi)存到內(nèi)存之間的數(shù)據(jù)拷貝。零拷貝有兩種實現(xiàn)方式:

  1. MMap
  2. SendFile

2.1.MMap

通過上文我們知道一次IO,數(shù)據(jù)會進行四次拷貝,MMap這種方式在將內(nèi)核段中的數(shù)據(jù)拷貝到用戶段的這次拷貝中,拷貝的不是數(shù)據(jù),而是數(shù)據(jù)的映射,這樣在用戶段中進行數(shù)據(jù)處理完后,就不必再從用戶段拷貝回內(nèi)核段,從而減少了一次拷貝。

之所以能實現(xiàn)這樣的效果是得益于操作系統(tǒng)底層有兩種讀操作:

讀取數(shù)據(jù):常見的系統(tǒng)調(diào)用如 read()(用于文件描述符)或 recv()(用于套接字)用于從文件或套接字中讀取數(shù)據(jù)。這些系統(tǒng)調(diào)用從相應(yīng)的輸入源(如磁盤、網(wǎng)絡(luò)等)讀取數(shù)據(jù),并將其復(fù)制到應(yīng)用程序提供的緩沖區(qū)中。這種方式涉及了數(shù)據(jù)的復(fù)制,因為數(shù)據(jù)需要從內(nèi)核態(tài)復(fù)制到用戶態(tài)緩沖區(qū)中。

讀取映射:另一種方式是通過內(nèi)存映射(Memory Mapping)來實現(xiàn)讀取操作。通過將文件或設(shè)備的數(shù)據(jù)映射到進程的內(nèi)存區(qū)域中,應(yīng)用程序可以直接訪問內(nèi)存映射區(qū)域中的數(shù)據(jù),而無需使用傳統(tǒng)的 read() 系統(tǒng)調(diào)用。在這種情況下,應(yīng)用程序可以通過直接讀取內(nèi)存映射區(qū)域中的數(shù)據(jù)來獲取文件或設(shè)備的內(nèi)容,避免了中間的數(shù)據(jù)復(fù)制。

特別說明:

還是和上文類似,畫圖的問題。這里為了涵蓋,本地IO和網(wǎng)絡(luò)IO兩種情況,內(nèi)核段沒拆成幾個設(shè)備的不同地址空間,但是如果是從磁盤中讀,然后向網(wǎng)絡(luò)中寫,是跨了IO設(shè)備的,所以中間有個內(nèi)核段地址間的復(fù)制過程,如下圖:

2.2.SendFile

SendFile更狠,直接就不走用戶段,直接就是從內(nèi)核段的一個內(nèi)存地址復(fù)制到另一個內(nèi)存地址,主要是拿來進行網(wǎng)絡(luò)傳輸?shù)?,從本地磁盤讀數(shù)據(jù),讀到一個地址里,然后將這個地址里的數(shù)據(jù)復(fù)制給另一個IO設(shè)備的地址,這個地址就可以是網(wǎng)絡(luò)IO的地址。很明顯sendFile有一個弊病,就是沒走用戶段的話,數(shù)據(jù)沒辦法處理,所以其只是一種用于實現(xiàn)數(shù)據(jù)傳輸?shù)?"零拷貝" 技術(shù),而不能直接進行數(shù)據(jù)處理。并且SendFile還存在大小限制。

三、JAVA中的零拷貝

零拷貝需要進行系統(tǒng)調(diào)用才能實現(xiàn),很明顯要我們手寫實現(xiàn)零拷貝是很底層、很麻煩的,好在JAVA在NIO中封裝了mmap、SendFile兩種零拷貝的API,當我們想在JAVA中使用零拷貝時,直接調(diào)API即可。

很多同學(xué)在NIO中老是搞不明白channel和buffer的關(guān),容易暈,這里博主一句話總結(jié)一下:

JavaNlO中 的Channel就相當于操作系統(tǒng)中的內(nèi)核緩沖區(qū),而Buffer就相當于操作系統(tǒng)中的用戶緩沖區(qū)。

mmap:

MappedByteBuffer mappedByteBuffer = new RandomAccessFile(file, "r") 
                                 .getChannel() 
                                .map(FileChannel.MapMode.READ_ONLY, 0, len);

SendFile:

sendFile進行網(wǎng)絡(luò)傳輸:

FileChannel sourceChannel = new RandomAccessFile(sourceFile, "rw").getChannel();
SocketChannel socketChannel = SocketChannel.open(sa);
sourceChannel.transferTo(0, sourceChannel.size(), socketChannel);

sendFile進行文件拷貝:

try (FileChannel srcChannel = new FileInputStream(src).getChannel();
     FileChannel targetChannel = new FileInputStream(target).getChannel()) {
     srcChannel.transferTo(0, srcChannel.size(), targetChannel );
 } catch (IOException e) {
     e.printStackTrace();
 }

分享題目:對IO概念模糊:計算機IO過程與零拷貝
文章位置:http://www.dlmjj.cn/article/cojceog.html