零拷贝是什么_file.copy()

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


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)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • 挑战10个最难回答的Java面试题(附答案)

    译者:Yujiaaosegmentfault.com/a/1190000019962661推荐阅读(点击即可跳转阅读)1.SpringBoot内容聚合2.面试题内容聚合3.设计模式内容聚合4.Mybatis内容聚合5.多线程内容聚合这是我收集的10个最棘手的Java面试问题列表。这些问题主要来自Java核心部分,不涉及JavaEE相关问题。…

    2022年4月14日
  • c++语言入门教程–15字符串常见操作

    c++语言入门教程–15字符串常见操作

    2021年3月12日
  • 计算机的发展历史和发展趋势_对未来计算机展望

    计算机的发展历史和发展趋势_对未来计算机展望论计算机发展史及展望(3页)本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!9.9积分论计算机发展史及展望杨露斯黎炼四川大学,成都双流610207摘要:自从1945年世界上第一台电子计算机诞生以来,计算机技术迅猛发展,CPU的速度越来越快,体积越来越小,价格越来越低。未来光子、一轮趨级计算技术革命。关键词:计算机;发展史;前景展望中图分类号:G4文…

    2022年10月19日
  • 树莓派是什么?能干什么?

    树莓派是什么?能干什么?树莓派是什么?能干什么?一、什么是树莓派?二、树莓派和单片机的区别?三、树莓派使用的什么系统?四、树莓派的最基本操作方法?五、树莓派能干什么?六、玩树莓派能学到什么?一、什么是树莓派?树莓派是由树莓派基金会发布的卡片式电脑,起初的目的是为了让更多的孩子们可以学习计算机编程,但是发布以后受到了广大计算机爱好者的喜爱树莓派被称为卡片式电脑,顾名思义它可以安装操作系统,并且接上显示屏鼠标键盘就可以正常使用,在上面可以用python或者C语言编程并运行。二、树莓派和单片机的区别?树莓派是卡片式电脑可以装

    2022年6月8日
  • 使用DataBaseMetaData得到表的主键

    使用DataBaseMetaData得到表的主键try{   Stringuser=”ahcwtest”;   Stringpassword=”ahcwtest”;   Stringdriver=”oracle.jdbc.driver.OracleDriver”;   Stringurl=”jdbc:oracle:thin:@192.168.71.17:1521:orcl”;   Stringsql=”SEL

    2022年6月20日
  • 霍尔传感器测速代码_arduino直流电机调速

    霍尔传感器测速代码_arduino直流电机调速标题本人目前是一个大一菜鸟,零基础学的编码器方面,希望我的经验对你有些帮助。分享一下霍尔编码器电机的使用与测速,我用的是25GA-310直流减速电机带霍尔传感器。先来看一下最基本的接线方法————-S1与S2连接单片机上的S(我这里用的2号和3号,是中断引脚);——G与V连接单片机上的G与V(对着接就行);——VM与GM接航模电池的正极与负极;测速…

    2022年10月1日

发表回复

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

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