零拷贝是什么_file.copy()

零拷贝是什么_file.copy()一、DMAio读写有两种方式:中断 DMA用户进程发起数据读取请求 系统调度为该进程分配cpu cpu向io控制器(ide,scsi)发送io请求 用户进程等待io完成,让出cpu 系统调度cpu执行其他任务 数据写入至io控制器的缓冲寄存器 缓冲寄存器满了向cpu发出中断信号 cpu读取数据至内存通过中断,cpu需要拷贝数据。2、DMA用户进程发起…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、DMA

io读写有两种方式:

  • 中断
  • DMA

零拷贝是什么_file.copy()

  1. 用户进程发起数据读取请求
  2. 系统调度为该进程分配cpu
  3. cpu向io控制器(ide,scsi)发送io请求
  4. 用户进程等待io完成,让出cpu
  5. 系统调度cpu执行其他任务
  6. 数据写入至io控制器的缓冲寄存器
  7. 缓冲寄存器满了向cpu发出中断信号
  8. cpu读取数据至内存

通过中断,cpu需要拷贝数据。

2、DMA

零拷贝是什么_file.copy()

  1. 用户进程发起数据读取请求
  2. 系统调度为该进程分配cpu
  3. cpu向DMA发送io请求
  4. 用户进程等待io完成,让出cpu
  5. 系统调度cpu执行其他任务
  6. 数据写入至io控制器的缓冲寄存器
  7. DMA不断获取缓冲寄存器中的数据(需要cpu时钟)
  8. 传输至内存(需要cpu时钟)
  9. 所需的全部数据获取完毕后向cpu发出中断信号

减少cpu中断,不用cpu拷贝数据,把数据拷贝这类工作从cpu中解放出来。

二、数据传输1

在一个web系统中从一个文件中读出数据并将数据传输到网络上另一程序的场景,有两种方式:

1、传统方式:

读取数据后并通过网络发送 所发生的数据拷贝,java代码如下:

File.read(fileDesc, buf, len);
Socket.send(socket, buf, len);

这里主要使用了linux底层的read()和write()两个系统调用,整个流程如下图:

零拷贝是什么_file.copy()

  • 一个read系统调用后,DMA执行了一次数据拷贝,从磁盘到内核空间
  • read结束后,发生第二次数据拷贝,由cpu将数据从内核空间拷贝至用户空间
  • send系统调用,cpu发生第三次数据拷贝,由cpu将数据从用户空间拷贝至内核空间(socket缓冲区)
  • send系统调用结束后,DMA执行第四次数据拷贝,将数据从内核拷贝至协议引擎

整个过程有四次数据拷贝,并且每个过程都发生一次上下文切换。

2、sendfile(零拷贝):

上面的方式我们没有对文件内容做任何修改,那么在内核空间和用户空间来回拷贝数据无疑就是一种浪费,而零拷贝主要就是为了解决这种低效性。java代码如下:

transferTo(position, count, writableChannel);

这里主要依赖linux底层sendfile()调用。Linux 2.1 版本提供了sendfile函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer。流程如下:

零拷贝是什么_file.copy()

  • DMA从拷贝至内核缓冲区
  • cpu将数据从内核缓冲区拷贝至内核空间(socket缓冲区)
  • DMA将数据从内核拷贝至协议引擎

这三个过程中共发生三次数据拷贝,2次上下文切换,分别为发起读取文件和发送数据。

3、进一步优化:

上面的方式尚未达到我们的零拷贝要求。如果底层网络接口卡支持收集操作 的话,那么我们就可以进一步减少内核的数据复制。在 Linux 内核 2.4 及后期版本中,套接字缓冲区描述符就做了相应调整,以满足该需求。这种方法不仅可以减少多个上下文切换,还可以消除需要涉及 CPU 的重复的数据拷贝。对于用户方面,用法还是一样的,整个流程如下:

零拷贝是什么_file.copy()

  • MA从拷贝至内核缓冲区
  • 将数据的位置和长度的信息的描述符增加至内核空间(socket缓冲区)
  • DMA将数据从内核拷贝至协议引擎

整个过程共发生两次数据拷贝。

参考:

https://www.ibm.com/developerworks/cn/java/j-zerocopy/

https://www.cnblogs.com/z-sm/p/6547709.html

https://blog.csdn.net/xiaofei0859/article/details/74321216

https://www.cnblogs.com/stateis0/p/10960579.html

java零拷贝示例代码:

1、文件到文件:

class ZerocopyFile {
    @SuppressWarnings("resource")
    public static void transferToDemo(String from, String to) throws IOException {
        FileChannel fromChannel = new RandomAccessFile(from, "rw").getChannel();
        FileChannel toChannel = new RandomAccessFile(to, "rw").getChannel();

        long position = 0;
        long count = fromChannel.size();

        fromChannel.transferTo(position, count, toChannel);

        fromChannel.close();
        toChannel.close();
    }

    @SuppressWarnings("resource")
    public static void transferFromDemo(String from, String to) throws IOException {
        FileChannel fromChannel = new FileInputStream(from).getChannel();
        FileChannel toChannel = new FileOutputStream(to).getChannel();

        long position = 0;
        long count = fromChannel.size();

        toChannel.transferFrom(fromChannel, position, count);

        fromChannel.close();
        toChannel.close();
    }

    public static void main(String[] args) throws IOException {
        String from = "src/main/java/zerocopy/1.data";
        String to = "src/main/java/zerocopy/2.data";
        // transferToDemo(from,to);
        transferFromDemo(from, to);
    }
}

2、socket:

/**
 * disk-nic零拷贝
 */
class ZerocopyServer {
    ServerSocketChannel listener = null;

    protected void mySetup() {
        InetSocketAddress listenAddr = new InetSocketAddress(9026);

        try {
            listener = ServerSocketChannel.open();
            ServerSocket ss = listener.socket();
            ss.setReuseAddress(true);
            ss.bind(listenAddr);
            System.out.println("监听的端口:" + listenAddr.toString());
        } catch (IOException e) {
            System.out.println("端口绑定失败 : " + listenAddr.toString() + " 端口可能已经被使用,出错原因: " + e.getMessage());
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        ZerocopyServer dns = new ZerocopyServer();
        dns.mySetup();
        dns.readData();
    }

    private void readData() {
        ByteBuffer dst = ByteBuffer.allocate(4096);
        try {
            while (true) {
                SocketChannel conn = listener.accept();
                System.out.println("创建的连接: " + conn);
                conn.configureBlocking(true);
                int nread = 0;
                while (nread != -1) {
                    try {
                        nread = conn.read(dst);
                    } catch (IOException e) {
                        e.printStackTrace();
                        nread = -1;
                    }
                    dst.rewind();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class ZerocopyClient {
    public static void main(String[] args) throws IOException {
        ZerocopyClient sfc = new ZerocopyClient();
        sfc.testSendfile();
    }

    public void testSendfile() throws IOException {
        String host = "localhost";
        int port = 9026;
        SocketAddress sad = new InetSocketAddress(host, port);
        SocketChannel sc = SocketChannel.open();
        sc.connect(sad);
        sc.configureBlocking(true);

        String fname = "src/main/java/zerocopy/test.data";
        FileChannel fc = new FileInputStream(fname).getChannel();
        long start = System.nanoTime();
        long nsent = 0, curnset = 0;
        curnset = fc.transferTo(0, fc.size(), sc);
        System.out.println("发送的总字节数:" + curnset + " 耗时(ns):" + (System.nanoTime() - start));
        try {
            sc.close();
            fc.close();
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

三、数据传输2

还有一个零拷贝的例子mmap。传统方式使用read、write进行文件会产生用户态和内核态数据的拷贝,使用mmap,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。

这里只做一个介绍,具体mmap的原理、使用下次再说。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/191106.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vue vue-element-ui组件 layout布局系列学习(一)[通俗易懂]

    vue vue-element-ui组件 layout布局系列学习(一)[通俗易懂]本文仅供参考:首先你要掌握的基础知识:row行概念<el-row></el-row>col列概念<el-col></el-col>col组件的:span属性的布局调整,一共分为24栏:代码示例:<el-row><el-col:span=”24″><divclass=”g…

    2022年5月21日
    206
  • idea修改快捷键方法总结

    前言:使用idea也有一短时间了(算算也快2个月),在快捷键方面常用的基本上都熟悉了,现在有时间总结一下修改快捷键的方法,这对于idea老鸟来说简直是小菜,但是对于菜鸟来还是有些帮助的一:切换快捷键注意:idea内置的许多IDE的快捷键,假如你是从其他IDE转过来的,但是有不想放弃自己以前已经习惯的那套快捷键。那么你可以直接切换到你以前IDE的快捷键,方法如下:1.打开设置中心:file–>Se

    2022年4月5日
    690
  • iis命令停止启动_更新并重启怎么取消

    iis命令停止启动_更新并重启怎么取消直接使用CMD我们可以操作很多事情,比如启动IIS,重启IIS,停止IIS重启IIS服务器,开始->运行->cmd(以下列出相关操作命令):iisreset /RESTART停止后启动iisreset/START启动IIS(如果停止)iisreset/STOP停止IIS(如果启动)iisreset/REBOOT重启电脑iisreset/REB…

    2025年5月23日
    0
  • JAVA事件适配器的作用

    JAVA事件适配器的作用适配器 其实从接口事件演变尔来的。相当于触发器,说简单点,它就是一些动作。例如说鼠标的按下点击还有键盘等等。适配器就是实现接口事件的类不过,不是真的实现,只是空实现,没有具体的方法体。适配器主要是为了方便程序员操作,避免了代码的重复性。只要一个对象或者属性添加了这个适配器,那么它就会监视这对象或属性。例如说一个按纽。按纽添加一个MouseAdap

    2022年5月4日
    50
  • photoshop实例实战(入门级)教程

    photoshop实例实战(入门级)教程PS对街拍女孩照片增加质感(2019-03-1917:57)PS制作水火相溶特效文字图片(2019-03-1917:49)PS制作简洁漂亮的立体抽丝文字(2019-03-1917:16)P

    2022年7月2日
    20
  • 配置springboot项目使用外部tomcat

    配置springboot项目使用外部tomcat在pom文件中添加依赖<!–使用自带的tomcat–><dependency><groupId>org.springframework.boot</

    2022年8月16日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号