亚洲欧美日韩丝袜另类_欧美va亚洲va国产综合_亚洲香蕉毛片久久网站老妇人_国产成+人+综合+亚洲欧美丁香花

您的位置:首頁>智東西 >

搞明白什么是零拷貝,就是這么簡單

來源:古時的風箏  

我們總會在各種地方看到零拷貝,那零拷貝到底是個什么東西。

接下來,讓我們來理一理啊。

拷貝說的是計算機里的 I/O 操作,也就是數據的讀寫操作。計算機可是一個復雜的家伙,包括軟件和硬件兩大部分,軟件主要指操作系統、驅動程序和應用程序。硬件那就多了,CPU、內存、硬盤等等一大堆東西。


(資料圖片僅供參考)

這么復雜的設備要進行讀寫操作,其中繁瑣和復雜程度可想而知。

傳統I/O的讀寫過程

如果要了解零拷貝,那就必須要知道一般情況下,計算機是如何讀寫數據的,我把這種情況稱為傳統 I/O。

數據讀寫的發起者是計算機中的應用程序,比如我們常用的瀏覽器、辦公軟件、音視頻軟件等。

而數據的來源呢,一般是硬盤、外部存儲設備或者是網絡套接字(也就是網絡上的數據通過網口+網卡的處理)。

過程本來是很復雜的,所以大學課程里要通過《操作系統》、《計算機組成原理》來專門講計算機的軟硬件。

簡化版讀操作流程

那么細的沒辦法講來,所以,我們把這個讀寫過程簡化一下,忽略大多數細節,只講流程。

圖片

上圖是應用程序進行一次讀操作的過程。

應用程序先發起讀操作,準備讀取數據了;內核將數據從硬盤或外部存儲讀取到內核緩沖區;內核將數據從內核緩沖區拷貝到用戶緩沖區;應用程序讀取用戶緩沖區的數據進行處理加工;詳細的讀寫操作流程

下面是一個更詳細的 I/O 讀寫過程。這個圖可好用極了,我會借助這個圖來厘清 I/O 操作的一些基礎但非常重要的概念。

圖片

先看一下這個圖,上面紅粉色部分是讀操作,下面藍色部分是寫操作。

如果一下子看著有點兒迷糊的話,沒關系,看看下面幾個概念就清楚了。

應用程序

就是安裝在操作系統上的各種應用。

系統內核

系統內核是一些列計算機的核心資源的集合,不僅包括CPU、總線這些硬件設備,也包括進程管理、文件管理、內存管理、設備驅動、系統調用等一些列功能。

外部存儲

外部存儲就是指硬盤、U盤等外部存儲介質。

內核態內核態是操作系統內核運行的模式,當操作系統內核執行特權指令時,處于內核態。在內核態下,操作系統內核擁有最高權限,可以訪問計算機的所有硬件資源和敏感數據,執行特權指令,控制系統的整體運行。內核態提供了操作系統管理和控制計算機硬件的能力,它負責處理系統調用、中斷、硬件異常等核心任務。用戶態

這里的用戶可以理解為應用程序,這個用戶是對于計算機的內核而言的,對于內核來說,系統上的各種應用程序會發出指令來調用內核的資源,這時候,應用程序就是內核的用戶。

用戶態是應用程序運行的模式,當應用程序執行普通的指令時,處于用戶態。在用戶態下,應用程序只能訪問自己的內存空間和受限的硬件資源,無法直接訪問操作系統的敏感數據或控制計算機的硬件設備。用戶態提供了一種安全的運行環境,確保應用程序之間相互隔離,防止惡意程序對系統造成影響。模式切換

計算機為了安全性考慮,區分了內核態和用戶態,應用程序不能直接調用內核資源,必須要切換到內核態之后,讓內核來調用,內核調用完資源,再返回給應用程序,這個時候,系統在切換會用戶態,應用程序在用戶態下才能處理數據。

上述過程其實一次讀和一次寫都分別發生了兩次模式切換。

圖片

內核緩沖區

內核緩沖區指內存中專門用來給內核直接使用的內存空間。可以把它理解為應用程序和外部存儲進行數據交互的一個中間介質。

應用程序想要讀外部數據,要從這里讀。應用程序想要寫入外部存儲,要通過內核緩沖區。

用戶緩沖區

用戶緩沖區可以理解為應用程序可以直接讀寫的內存空間。因為應用程序沒法直接到內核讀寫數據, 所以應用程序想要處理數據,必須先通過用戶緩沖區。

磁盤緩沖區

磁盤緩沖區是計算機內存中用于暫存從磁盤讀取的數據或將數據寫入磁盤之前的臨時存儲區域。它是一種優化磁盤 I/O 操作的機制,通過利用內存的快速訪問速度,減少對慢速磁盤的頻繁訪問,提高數據讀取和寫入的性能和效率。

PageCachePageCache 是 Linux 內核對文件系統進行緩存的一種機制。它使用空閑內存來緩存從文件系統讀取的數據塊,加速文件的讀取和寫入操作。當應用程序或進程讀取文件時,數據會首先從文件系統讀取到 PageCache 中。如果之后再次讀取相同的數據,就可以直接從 PageCache 中獲取,避免了再次訪問文件系統。同樣,當應用程序或進程將數據寫入文件時,數據會先暫存到 PageCache 中,然后由 Linux 內核異步地將數據寫入磁盤,從而提高寫入操作的效率。再說數據讀寫操作流程

上面弄明白了這幾個概念后,再回過頭看一下那個流程圖,是不是就清楚多了。

讀操作首先應用程序向內核發起讀請求,這時候進行一次模式切換了,從用戶態切換到內核態;內核向外部存儲或網絡套接字發起讀操作;將數據寫入磁盤緩沖區;系統內核將數據從磁盤緩沖區拷貝到內核緩沖區,順便再將一份(或者一部分)拷貝到 PageCache;內核將數據拷貝到用戶緩沖區,供應用程序處理。此時又進行一次模態切換,從內核態切換回用戶態;寫操作應用程序向內核發起寫請求,這時候進行一次模式切換了,從用戶態切換到內核態;內核將要寫入的數據從用戶緩沖區拷貝到 PageCache,同時將數據拷貝到內核緩沖區;然后內核將數據寫入到磁盤緩沖區,從而寫入磁盤,或者直接寫入網絡套接字。瓶頸在哪里

但是傳統I/O有它的瓶頸,這才是零拷貝技術出現的緣由。瓶頸是啥呢,當然是性能問題,太慢了。尤其是在高并發場景下,I/O性能經常會卡脖子。

那是什么地方耗時了呢?

數據拷貝

在傳統 I/O 中,數據的傳輸通常涉及多次數據拷貝。數據需要從應用程序的用戶緩沖區復制到內核緩沖區,然后再從內核緩沖區復制到設備或網絡緩沖區。這些數據拷貝過程導致了多次內存訪問和數據復制,消耗了大量的 CPU 時間和內存帶寬。

用戶態和內核態的切換

由于數據要經過內核緩沖區,導致數據在用戶態和內核態之間來回切換,切換過程中會有上下文的切換,如此一來,大大增加了處理數據的復雜性和時間開銷。

每一次操作耗費的時間雖然很小,但是當并發量高了以后,積少成多,也是不小的開銷。所以要提高性能、減少開銷就要從以上兩個問題下手了。

這時候,零拷貝技術就出來解決問題了。

什么是零拷貝

問題出來數據拷貝和模態切換上。

但既然是 I/O 操作,不可能沒有數據拷貝的,只能減少拷貝的次數,還有就是盡量將數據存儲在離應用程序(用戶緩沖區)更近的地方。

而區分用戶態和內核態有其他更重要的原因,不可能單純為了 I/O 效率就改變這種設計吧。那也只能盡量減少切換的次數。

零拷貝的理想狀態就是操作數據不用拷貝,但是顯示情況下并不一定真的就是一次復制操作都沒有,而是盡量減少拷貝操作的次數。

要實現零拷貝,應該從下面這三個方面入手:

盡量減少數據在各個存儲區域的復制操作,例如從磁盤緩沖區到內核緩沖區等;盡量減少用戶態和內核態的切換次數及上下文切換;使用一些優化手段,例如對需要操作的數據先緩存起來,內核中的 PageCache 就是這個作用;實現零拷貝方案直接內存訪問(DMA)

DMA 是一種硬件特性,允許外設(如網絡適配器、磁盤控制器等)直接訪問系統內存,而無需通過 CPU 的介入。在數據傳輸時,DMA 可以直接將數據從內存傳輸到外設,或者從外設傳輸數據到內存,避免了數據在用戶態和內核態之間的多次拷貝。

圖片

DMA1

如上圖所示,內核將數據讀取的大部分數據讀取操作都交個了 DMA 控制器,而空出來的資源就可以去處理其他的任務了。

sendfile

一些操作系統(例如 Linux)提供了特殊的系統調用,如 sendfile,在網絡傳輸文件時實現零拷貝。通過 sendfile,應用程序可以直接將文件數據從文件系統傳輸到網絡套接字或者目標文件,而無需經過用戶緩沖區和內核緩沖區。

如果不用sendfile,如果將A文件寫入B文件。

需要先將A文件的數據拷貝到內核緩沖區,再從內核緩沖區拷貝到用戶緩沖區;然后內核再將用戶緩沖區的數據拷貝到內核緩沖區,之后才能寫入到B文件;

而用了sendfile,用戶緩沖區和內核緩沖區的拷貝都不用了,節省了一大部分的開銷。

共享內存

使用共享內存技術,應用程序和內核可以共享同一塊內存區域,避免在用戶態和內核態之間進行數據拷貝。應用程序可以直接將數據寫入共享內存,然后內核可以直接從共享內存中讀取數據進行傳輸,或者反之。

圖片

通過共享一塊兒內存區域,實現數據的共享。就像程序中的引用對象一樣,實際上就是一個指針、一個地址。

內存映射文件(Memory-mapped Files)

內存映射文件直接將磁盤文件映射到應用程序的地址空間,使得應用程序可以直接在內存中讀取和寫入文件數據,這樣一來,對映射內容的修改就是直接的反應到實際的文件中。

當文件數據需要傳輸時,內核可以直接從內存映射區域讀取數據進行傳輸,避免了數據在用戶態和內核態之間的額外拷貝。

雖然看上去感覺和共享內存沒什么差別,但是兩者的實現方式完全不同,一個是共享地址,一個是映射文件內容。

Java 實現零拷貝的方式

Java 標準的 IO 庫是沒有零拷貝方式的實現的,標準IO就相當于上面所說的傳統模式。只是在 Java 推出的 NIO 中,才包含了一套新的 I/O 類,如ByteBuffer和Channel,它們可以在一定程度上實現零拷貝。

ByteBuffer:可以直接操作字節數據,避免了數據在用戶態和內核態之間的復制。

Channel:支持直接將數據從文件通道或網絡通道傳輸到另一個通道,實現文件和網絡的零拷貝傳輸。

借助這兩種對象,結合 NIO 中的API,我們就能在 Java 中實現零拷貝了。

首先我們先用傳統 IO 寫一個方法,用來和后面的 NIO 作對比,這個程序的目的很簡單,就是將一個100M左右的PDF文件從一個目錄拷貝到另一個目錄。

public static void ioCopy() {  try {    File sourceFile = new File(SOURCE_FILE_PATH);    File targetFile = new File(TARGET_FILE_PATH);    try (FileInputStream fis = new FileInputStream(sourceFile);         FileOutputStream fos = new FileOutputStream(targetFile)) {      byte[] buffer = new byte[1024];      int bytesRead;      while ((bytesRead = fis.read(buffer)) != -1) {        fos.write(buffer, 0, bytesRead);      }    }    System.out.println("傳輸 " + formatFileSize(sourceFile.length()) + " 字節到目標文件");  } catch (IOException e) {    e.printStackTrace();  }}

下面是這個拷貝程序的執行結果,109.92M,耗時1.29秒。

傳輸 109.92 M 字節到目標文件 耗時: 1.290 秒

FileChannel.transferTo() 和 transferFrom()

FileChannel 是一個用于文件讀寫、映射和操作的通道,同時它在并發環境下是線程安全的,基于 FileInputStream、FileOutputStream 或者 RandomAccessFile 的 getChannel() 方法可以創建并打開一個文件通道。FileChannel 定義了 transferFrom() 和 transferTo() 兩個抽象方法,它通過在通道和通道之間建立連接實現數據傳輸的。

這兩個方法首選用 sendfile 方式,只要當前操作系統支持,就用 sendfile,例如Linux或MacOS。如果系統不支持,例如windows,則采用內存映射文件的方式實現。

transferTo()

下面是一個 transferTo 的例子,仍然是拷貝那個100M左右的 PDF,我的系統是 MacOS。

public static void nioTransferTo() {  try {    File sourceFile = new File(SOURCE_FILE_PATH);    File targetFile = new File(TARGET_FILE_PATH);    try (FileChannel sourceChannel = new RandomAccessFile(sourceFile, "r").getChannel();         FileChannel targetChannel = new RandomAccessFile(targetFile, "rw").getChannel()) {      long transferredBytes = sourceChannel.transferTo(0, sourceChannel.size(), targetChannel);      System.out.println("傳輸 " + formatFileSize(transferredBytes) + " 字節到目標文件");    }  } catch (IOException e) {    e.printStackTrace();  }}

只耗時0.536秒,快了一倍。

傳輸 109.92 M 字節到目標文件 耗時: 0.536 秒

transferFrom()

下面是一個 transferFrom 的例子,仍然是拷貝那個100M左右的 PDF,我的系統是 MacOS。

public static void nioTransferFrom() {  try {    File sourceFile = new File(SOURCE_FILE_PATH);    File targetFile = new File(TARGET_FILE_PATH);    try (FileChannel sourceChannel = new RandomAccessFile(sourceFile, "r").getChannel();         FileChannel targetChannel = new RandomAccessFile(targetFile, "rw").getChannel()) {      long transferredBytes = targetChannel.transferFrom(sourceChannel, 0, sourceChannel.size());      System.out.println("傳輸 " + formatFileSize(transferredBytes) + " 字節到目標文件");    }  } catch (IOException e) {    e.printStackTrace();  }}

執行時間

傳輸 109.92 M 字節到目標文件 耗時: 0.603 秒

Memory-Mapped Files

Java 的 NIO 也支持內存映射文件(Memory-mapped Files),通過FileChannel.map()實現。

下面是一個FileChannel.map()的例子,仍然是拷貝那個100M左右的 PDF,我的系統是 MacOS。

public static void nioMap(){        try {            File sourceFile = new File(SOURCE_FILE_PATH);            File targetFile = new File(TARGET_FILE_PATH);            try (FileChannel sourceChannel = new RandomAccessFile(sourceFile, "r").getChannel();                 FileChannel targetChannel = new RandomAccessFile(targetFile, "rw").getChannel()) {                long fileSize = sourceChannel.size();                MappedByteBuffer buffer = sourceChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize);                targetChannel.write(buffer);                System.out.println("傳輸 " + formatFileSize(fileSize) + " 字節到目標文件");            }        } catch (IOException e) {            e.printStackTrace();        }    }

執行時間:

傳輸 109.92 M 字節到目標文件 耗時: 0.663 秒

關鍵詞:

最新文章
亚洲欧美日韩丝袜另类_欧美va亚洲va国产综合_亚洲香蕉毛片久久网站老妇人_国产成+人+综合+亚洲欧美丁香花

      一区二区三区成人在线视频| 国产成人高清在线| av一区二区三区四区| 亚洲女爱视频在线| 51精品久久久久久久蜜臀| 中文字幕欧美一区| 狠狠色丁香婷婷综合| 欧美精彩视频一区二区三区| 91黄色在线观看| 国产视频911| 老司机一区二区| 中文字幕欧美日韩一区| 欧美视频在线观看一区| 国产精品午夜春色av| 久久激五月天综合精品| 中文无字幕一区二区三区| 欧美日韩免费一区二区三区| 亚洲欧洲色图综合| 国产成人在线免费| 亚洲尤物视频在线| 久久精品日韩一区二区三区| 美女视频网站久久| 国产精品欧美综合在线| 91精品国产综合久久精品麻豆| 中文字幕一区二区三区在线不卡 | 中文字幕中文字幕中文字幕亚洲无线| 免费观看日韩av| 国产精品素人一区二区| 欧美一级电影网站| 五月天欧美精品| 国产无遮挡一区二区三区毛片日本| 欧美性一区二区| 亚洲在线免费播放| 91麻豆.com| 欧美日韩一区二区三区高清| 亚洲免费在线观看视频| 99久久er热在这里只有精品66| 色婷婷精品大在线视频| 中文字幕亚洲区| 99九九99九九九视频精品| 欧美视频在线一区二区三区| 亚洲午夜av在线| 国产喷白浆一区二区三区| 欧美一区二区免费观在线| 天堂精品中文字幕在线| 国产精品传媒入口麻豆| 精品少妇一区二区三区视频免付费 | 国产精品免费视频观看| 精品久久久久久久一区二区蜜臀| 蜜臀久久99精品久久久画质超高清| 国产精品国产三级国产aⅴ中文| 精品免费国产一区二区三区四区| 看片的网站亚洲| 亚洲午夜免费电影| 成人免费视频在线观看| 久久青草国产手机看片福利盒子| 欧美一级艳片视频免费观看| 男女激情视频一区| 洋洋成人永久网站入口| 亚洲色图丝袜美腿| 国产亚洲欧美激情| 亚洲精品一区二区三区香蕉| 国产福利一区二区三区视频在线| 91久久精品日日躁夜夜躁欧美| 亚洲二区在线视频| 综合色中文字幕| 中文av一区特黄| 91玉足脚交白嫩脚丫在线播放| 制服丝袜在线91| 国产一区在线观看视频| 色94色欧美sute亚洲线路二| 五月天视频一区| 亚洲伊人伊色伊影伊综合网 | 亚洲日本va在线观看| 亚洲欧洲精品一区二区三区| 久久精品视频在线免费观看| 精品国产乱码久久| 成人激情综合网站| 欧美一卡二卡在线| 国产精品一区2区| 欧美日韩国产色站一区二区三区| 免费在线观看成人| 天天爽夜夜爽夜夜爽精品视频| 亚洲.国产.中文慕字在线| 亚洲制服丝袜av| 亚洲国产精品久久久久婷婷884 | 国产欧美日产一区| 国产精品国产三级国产普通话蜜臀 | 久久亚洲一级片| 2023国产精品视频| 99v久久综合狠狠综合久久| 精品国产精品网麻豆系列| 成人激情免费电影网址| 精品奇米国产一区二区三区| 成人久久18免费网站麻豆| 日韩视频免费观看高清完整版在线观看| 国产毛片精品一区| 91精品国产欧美一区二区成人 | 欧美一二三区在线观看| 国产91精品一区二区麻豆亚洲| 欧美精品一级二级三级| 国产精品一区在线| 日韩一级黄色大片| 91一区在线观看| 久久久久久亚洲综合影院红桃 | 色婷婷亚洲一区二区三区| 奇米综合一区二区三区精品视频| 午夜欧美大尺度福利影院在线看| 日韩精品国产精品| 欧美三日本三级三级在线播放| 国内精品伊人久久久久影院对白| 91精品国产美女浴室洗澡无遮挡| 懂色av一区二区三区免费看| 精品国产成人在线影院| 久久无码av三级| 日韩一区欧美一区| 亚洲在线视频一区| 美女视频黄久久| 欧美一级二级三级乱码| 久久综合久久鬼色| 日韩美女视频一区| 亚洲一区二区三区中文字幕在线| 日本欧洲一区二区| 欧美一区二区三区的| www久久久久| 成人免费一区二区三区在线观看 | 国产精品―色哟哟| 亚洲国产另类精品专区| 欧美午夜精品免费| 99久久亚洲一区二区三区青草| 欧美国产日韩一二三区| 亚洲日本中文字幕区| 日韩精品视频网站| 91精品国产乱| 久久精品一级爱片| 亚洲国产一区二区视频| 欧美性感一区二区三区| 播五月开心婷婷综合| 国产精品久久久爽爽爽麻豆色哟哟| 亚洲精品一二三区| 国内精品嫩模私拍在线| www国产精品av| 亚洲欧美日韩久久| 久久精品免费观看| 欧美精品一区二区久久久| 国产精品九色蝌蚪自拍| 日韩二区在线观看| 日韩欧美视频一区| 国产精品久久久久久久第一福利 | 在线视频综合导航| 不卡电影一区二区三区| 成人欧美一区二区三区视频网页 | 波多野结衣中文字幕一区二区三区 | 亚洲一区二区三区美女| 国产老妇另类xxxxx| 国产亚洲va综合人人澡精品| 亚洲综合色丁香婷婷六月图片| 韩国三级中文字幕hd久久精品| 久久久久久久久一| 亚洲图片欧美一区| 国产不卡视频在线播放| 亚洲色图欧美激情| 欧美三片在线视频观看| 国产肉丝袜一区二区| 青青青爽久久午夜综合久久午夜| 精品少妇一区二区三区视频免付费 | 91搞黄在线观看| 国产日韩三级在线| 蜜臀av在线播放一区二区三区| 26uuu国产在线精品一区二区| 亚洲精品精品亚洲| 国产69精品久久久久毛片| 亚洲乱码国产乱码精品精98午夜| 欧美日韩亚洲综合一区二区三区| 国产丝袜美腿一区二区三区| 美女国产一区二区| 国产农村妇女毛片精品久久麻豆 | 国产亚洲欧美日韩日本| 蜜桃传媒麻豆第一区在线观看| 国产日产精品1区| 欧美中文字幕一区二区三区| 欧美国产丝袜视频| 久久99精品国产麻豆婷婷| 国产精品久久久久久户外露出| 精品视频一区 二区 三区| 国产精品免费久久久久| 国产成人免费xxxxxxxx| 亚洲国产精品人人做人人爽| 欧美电影免费观看完整版 | 日韩精品午夜视频| 国产精品美女久久久久久久网站| 欧美性猛交xxxx黑人交| 中文字幕一区二区三区四区| 国产a视频精品免费观看| 亚洲一级片在线观看| 久久久亚洲午夜电影| 在线观看视频欧美| 亚洲欧洲成人精品av97| 成人涩涩免费视频| 日本成人在线不卡视频|