【HBZ】高性能zeroCopy零拷贝与普通IO差距与原理

news2024/11/27 22:40:23

简介

  1. 随着IO不断地发展,无论哪种拷贝方式,DMA从磁盘拷贝数据到内核缓冲区,都会拷贝多一些数据, 不会只拷贝用户态的指定size的数据,而是会将目标数据的临近数据也都拷贝到内核缓冲区,以便下次IO操作可以直接从内核缓冲区获取,无需再次走磁盘

普通IO的拷贝流程

  1. 普通的IO拷贝,要经历4次CPU上下文切换 与 4次拷贝操作
  2. 内核缓冲区拷贝数据到用户缓冲区是用户态指令是多少size,就拷贝多少size回去
  3. 每次拷贝的数据都恰好是需要的数据,因此每次需要查询数据时,都要走一遍整个过程,所以性能非常慢

在这里插入图片描述

普通IO-Buffered的拷贝流程

  1. buffered方式为什么比普通IO更快?
    答:buffered在内核缓冲区拷贝到用户缓冲区的时候,会将目标数据 及 目标临近的数据一同拷贝到用户缓冲区,这样下一次如果查询数据命中临近的数据,就不会在走内核态,所以会更快一些
    在这里插入图片描述

零拷贝-mmap流程

  1. mmap方式的零拷贝会经历(4次上下问切换 与 3次拷贝)
  2. 由图可见, 内核缓冲区不会拷贝数据到用户缓冲区,而且用户 与 内核缓冲区共同指向一块虚拟内存地址,而数据会保存在虚拟内存所对应的物理内存地址中。并且用户态向socket缓冲区发起指令也不需要携带数据拷贝,而真正的数据拷贝是socket缓冲区直接从内核缓冲区中拷贝数据,所以减少了两次拷贝,在内核缓冲区与socket缓冲区又追加了一层拷贝,总体少了一次拷贝
    在这里插入图片描述

零拷贝-sendfile流程

  1. sendfile()方式的零拷贝经历(2次切换,2次拷贝)
  2. 注意: 第三步拷贝偏移量本质也是拷贝,但拷贝的是内存偏移量,数据量极小,所以忽略不计
  3. 注意2:sendfiel()这种方式仅适用于本地相互拷贝,不适用于网络IO
  4. socket缓冲区获取数据,是从一块物理内存中直接获取,而这块物理内存是【内核缓冲区】 和 【socket缓冲区】共同映射的地址,因此数据是通过内存地址直接获取,而并非拷贝一份,所以只有2次拷贝
    在这里插入图片描述

java代码实现4中拷贝

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

// 
普通IO
    @Test
    public void publicIo() throws FileNotFoundException {

        try (InputStream inputStream = new FileInputStream("D:\\zeroCopyTest\\zeroCopyFile.zip");
             OutputStream outputStream = new FileOutputStream("D:\\zeroCopyTest\\zeroCopyOutstream.zip");){

            byte[] bytes = new byte[1024];
            int  len;

            long start = System.currentTimeMillis();
            while ((len = inputStream.read(bytes)) != -1){
                outputStream.write(bytes,0,len);
            }
            long end = System.currentTimeMillis();

            System.out.println("耗费时间: " + (end - start));

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

// 
普通io-buffered
    @Test
    public void bufferIo() throws FileNotFoundException {

        try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("D:\\zeroCopyTest\\zeroCopyFile.zip")) ;
             BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("D:\\zeroCopyTest\\zeroCopyOutstream.zip"));){

            byte[] bytes = new byte[1024];
            int  len;

            long start = System.currentTimeMillis();
            while ((len = inputStream.read(bytes)) != -1){
                outputStream.write(bytes,0,len);
            }
            long end = System.currentTimeMillis();

            System.out.println("耗费时间: " + (end - start));

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

// 零拷贝-mmap
    @Test
    public void mmapCopyFile(){

        long start = System.currentTimeMillis();
        try(
                FileChannel inputChannel = new FileInputStream("D:\\zeroCopyTest\\zeroCopyFile.zip").getChannel();
                FileChannel outputChannel = new RandomAccessFile("D:\\zeroCopyTest\\zeroCopyOutstream.zip","rw").getChannel();
        ){
            long size = inputChannel.size();

            MappedByteBuffer mapInBuffer = inputChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
            MappedByteBuffer mapOutBuffer = outputChannel.map(FileChannel.MapMode.READ_WRITE, 0, size);

            byte[] buffer = new byte[1024]; // 设置数组大小为1024
            int len;

            while ((len = inputChannel.read(ByteBuffer.wrap(buffer))) != -1) {
                byte b = mapInBuffer.get(len);
                mapOutBuffer.put(b);
            }
            long end = System.currentTimeMillis();
            System.out.println("耗费时间: " + (end - start));

        }catch (Exception e){
            throw new RuntimeException(e);
        }

    }
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

// 零拷贝-sendfile()
 @Test
    public void sendfileCopyFile(){
        long start = System.currentTimeMillis();
        try(
                FileChannel inputChannel = new FileInputStream("D:\\zeroCopyTest\\zeroCopyFile.zip").getChannel();
                FileChannel outputChannel = new FileOutputStream("D:\\zeroCopyTest\\zeroCopyOutstream.zip").getChannel();
        ){

            // 方式1: 针对小于2GB文件
            // 实际拷贝的大小(只会拷贝2GB, inputChannel.size() = 3GB, 那realSize也就 = 2GB)
            //  参数1: 从哪里开始拷贝, 参数2: 拷贝多少个字节, 参数3: 拷贝到哪里去
//            long realSize = inputChannel.transferTo(0, inputChannel.size(), outputChannel);


            // 方式2: 针对大于2GB文件, 分多次读写
            // 获取文件总大小
            long size = inputChannel.size();
            for(long left = size; left > 0;){

                // 返回真实拷贝的大小
                // 这里position起始拷贝位置,改为size-left(即总大小 - 剩余大小的位置), 参数2: left就是拷贝多少大小
                long transferSize = inputChannel.transferTo(size - left, left, outputChannel);
                // 计算出还剩余的大小
                left -= transferSize;

            }
            long end = System.currentTimeMillis();
            System.out.println("耗费时间: " + (end - start));

        }catch (Exception e){
            throw new RuntimeException(e);
        }

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1903201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python】python客户信息审计风险决策树算法分类预测(源码+数据集+论文)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

unity3d:Shader知识点,矩阵,函数,坐标转换,Tags,半透明,阴影,深度,亮度,优化

基本结构 Shader "MyShaderName" {Properties {// 属性}SubShader {// 针对显卡A的SubShaderPass {// 设置渲染状态和标签Tags { "LightMode""ForwardBase" }// 开始Cg代码片段CGPROGRAM// 该代码片段的编译指令,例如:#p…

浪潮信息元脑服务器支持英特尔®至强®6能效核处理器 展现强劲性能

如今,服务器作为数字经济的核心基础设施,正面临着前所未有的挑战和机遇。作为服务器领域的领军企业,浪潮信息始终站在行业前沿,不断推陈出新,以满足客户日益增长的需求。近日,浪潮信息再次展现技术实力&…

Java学习十四—Java8特性之Lambda表达式

一、简介 Java 8 引入了 Lambda 表达式,它是一种更简洁、更便于使用的函数式编程特性。Lambda 表达式允许将函数作为方法的参数(函数式接口的实例)传递给某个方法,或者将代码像数据一样进行传递。 ‍ lambda是一个匿名函数&#…

Kubernetes分享

幂等性(Idempotency) 介绍 简单来说,幂等性幂等性(Idempotency)是计算机科学中的一个重要概念,特别是在分布式系统和网络应用中。指的是某个操作可以重复执行多次,但其结果是相同的,不会因为多次执行而改变系统的状态。 https://…

解决后端限制导致前端配置跨域仍请求失败报504的问题

文章目录 问题一、通过配置跨域方式二、直接真实接口请求三、解决方式四、后端这样做的原因 总结 问题 前端项目设置跨域proxy处理,接口请求不会报跨域,但是接口请求报了504,这种情况如何处理呢,后端又为何要这么做,下…

2007-2022年中国各企业数字化转型与供应链效率

企业数字化转型与供应链效率是现代企业管理和发展的两个关键方面。以下是对中国各企业数字化转型与供应链效率数据的介绍: 数据简介 企业数字化转型:指企业通过采用数字技术与创新方法,改造业务流程、组织结构和产品服务,以提升…

U盘非安全拔出后的格式化危机与数据拯救策略

在数字化时代,U盘作为便捷的数据携带工具,其重要性不言而喻。然而,许多用户在日常使用中往往忽视了安全退出的重要性,直接拔出U盘后再插入时可能会遭遇“需要格式化”的提示,这一状况不仅令人措手不及,更可…

STM32+ESP8266(ESP32)+MQTT+阿里云物联网平台

1、阿里云物联网平台 - 阿里云物联网平台配置 产品-设备-编辑物模型-设备端开发-查看上报数据 在产品上添加物模型,然后设备是继承自产品的,因此也具有物模型 添加产品、添加设备、产品上添加物模型 - 使用IOT Studio 绘制界面显示温度、湿度、灯开…

pdf怎么转换成图片格式文件,pdf文档怎么转换成图片格式

在数字化时代,pdf文件转换成图片格式是一种常见的操作,无论是在工作还是日常生活中,我们总会遇到需要将pdf文件转换为图片的需求。这可能是因为图片格式更易于分享、展示或编辑。那么,如何高效地将pdf转换成图片呢?本文…

CSRF靶场通关合集

目录 前言 CSRF漏洞总结 1.PiKachu靶场 1.1CSRF(get) 1.2 CSRF(post)请求 1.3 CSRF Token 2.DVWA靶场 难度低 难度中 难度高 前言 最近系统的将从web渗透到内网渗透的知识点做一个回顾,同时结合一些实战的案例来演示,下面是对刚开始学习时对靶场的一个总结. CSRF漏洞…

快速搭建发卡独立站(完全免费)

本文介绍如何使用开源项目,零成本,无需服务器的方式搭建一套自己的数字商品/发卡独立站,不需要任何开发能力,即便是小白用户也能搭建。 感兴趣可直接查看开源项目地址👉 https://github.com/iDataRiver/theme-basic …

sqlite 数据库 介绍

文章目录 前言一、什么是 SQLite ?二、语法三、SQLite 场景四、磁盘文件 前言 下载 目前已经出到了, Version 3.46.0 SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是…

Node 中基于 Koa 框架的 Web 服务搭建实战

前言 在《Node之Web服务 - 掘金 (juejin.cn)》一文中,我们使用 HTTP 模块构建了后端接口,从而实现了后端服务的开发。可以对此进行进一步优化 http模块代码回顾 const http require("http");const server http.createServer((req, res) > {if (reqUrl.pathna…

Simulated Annealing

模拟退火最大值算法: 初始化起始解 x 0 x_0 x0​ 、温度 t 0 t_0 t0​ 以及迭代次数 steps,计算初始值 y 0 y_0 y0​扰动产生新解 x 1 x_1 x1​, 计算对应函数值 y 1 y_1 y1​依据 Δ y y 1 − y 0 \Delta y y_1 - y_0 Δyy1​−y0​ 决策是否接…

element-ui输入框如何实现回显的多选样式?

废话不多说直接上效果&#x1f9d0; 效果图 <template><div><el-form:model"params"ref"queryForm"size"small":inline"true"label-width"68px"><el-form-item label"标签" prop"tag&q…

CurrentHashMap巧妙利用位运算获取数组指定下标元素

先来了解一下数组对象在堆中的存储形式【数组长度&#xff0c;数组元素类型信息等】 【存放元素对象的空间】 Ma 基础信息实例数据内存填充Mark Word,ClassPointer,数组长度第一个元素第二个元素固定的填充内容 所以我们想要获取某个下标的元素首先要获取这个元素的起始位置…

UEC++ 虚幻5第三人称射击游戏(二)

UEC++ 虚幻5第三人称射击游戏(二) 派生榴弹类武器 新建一个继承自Weapon的子类作为派生榴弹类武器 将Weapon类中的Fire函数添加virtual关键字变为虚函数让榴弹类继承重写 在ProjectileWeapon中重写Fire函数,新建生成投射物的模版变量 Fire函数重写逻辑 代码//生成的投射物U…

使用Spring Boot和自定义缓存注解优化应用性能

在现代应用开发中&#xff0c;缓存是提高系统性能和响应速度的关键技术之一。Spring Boot提供了强大的缓存支持&#xff0c;但有时我们需要更灵活的缓存控制。本文将介绍如何使用Spring Boot和自定义缓存注解来优化应用性能。 1. 为什么需要自定义缓存注解&#xff1f; Sprin…

CH12_函数和事件

第12章&#xff1a;Javascript的函数和事件 本章目标 函数的概念掌握常用的系统函数掌握类型转换掌握Javascript的常用事件 课程回顾 Javascript中的循环有那些&#xff1f;Javascript中的各个循环特点是什么&#xff1f;Javascript中的各个循环语法分别是什么&#xff1f;…