一、DMA

io读写有两种方式:

  • 中断
  • DMA

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

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

2、DMA

  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()两个系统调用,整个流程如下图:

  • 一个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。流程如下:

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

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

3、进一步优化:

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

  • 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的原理、使用下次再说。

零拷贝——sendfile相关推荐

  1. Linux 零拷贝 sendfile函数中文说明及实际操作

    Sendfile函数说明  #include  ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); sendfi ...

  2. sendfile:Linux中的零拷贝

    如今几乎每个人都听说过Linux中所谓的"零拷贝"特性,然而我经常碰到没有充分理解这个问题的人们.因此,我决定写一些文章略微深入的讲述这个问题,希望能将这个有用的特性解释清楚.在本 ...

  3. Kafka速度快的原因-sendfile零拷贝介绍

    所谓的零拷贝是指将数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手.零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换.对 Linux 操作系统而言,零拷贝技术依赖于底层 ...

  4. 零拷贝 zero-copy 原理

    引言 传统的 Linux 操作系统的标准 I/O 接口是基于数据拷贝操作的,即 I/O 操作会导致数据在操作系统内核地址空间的缓冲区和应用程序地址空间定义的缓冲区之间进行传输.这样做最大的好处是可以减 ...

  5. Linux下的零拷贝

    Reference:  https://segmentfault.com/a/1190000011989008 零拷贝是什么? 维基百科对"零拷贝"是这样描述的: "Ze ...

  6. 一篇文章彻底弄懂零拷贝底层原理

    前言 零拷贝是网络编程的关键,很多性能优化都离不开零拷贝,很多优秀的开源框架底层都用的零拷贝,如Netty.RocketMQ.Spark等 正文 1. 再看IO 在深入零拷贝机制之前,先来了解下传统B ...

  7. 7 张图,轻松掌握零拷贝原理

    零拷贝是老生常谈的问题啦,大厂非常喜欢问.比如Kafka为什么快,RocketMQ为什么快等,都涉及到零拷贝知识点.最近技术讨论群几个伙伴分享了阿里.虾皮的面试真题,也都涉及到零拷贝.因此本文将跟大家 ...

  8. 数据传输方式(零拷贝)

    目录 数据传输方式 早期阶段 接口模块 DMA 具有通道结构的阶段 具有I/O处理机的阶段 传统拷贝 零拷贝 在介绍零拷贝之前我们先说下在计算机系统中数据传输的方式. 数据传输方式 早期阶段 分散连接 ...

  9. 【Netty】mmap 和 sendFile 零拷贝原理

    文章目录 一. 零拷贝 简介 二. 传统 BIO 数据拷贝分析 ( 4拷贝 4切换 ) 三. mmap 内存映射 ( 3拷贝 4切换 ) 四. sendFile 函数 ( Linux 2.1 优化 ) ...

最新文章

  1. mysql innodb 索引结构_Mysql 学习笔记:InnoDB 索引结构浅析
  2. ASP.NET Core Identity 实战(1)——Identity 初次体验
  3. Windows内存的一些知识点
  4. Ubuntu默认不进入图形界面
  5. hystrix合并请求_Hystrix中的批处理(折叠)请求
  6. LeetCode 327. 区间和的个数(multiset二分查找/归并排序)
  7. Lambda 表达式详解~Streams API~Stream常见接口方法
  8. Mybatis中的动态SQL记录
  9. 铁路系统的在线检测系统讲座
  10. java 并发变量_二、Java多线程编程 (对象及变量的并发访问)
  11. 【Django 2021年最新版教程1】windows10+python3.9.5+pycharm2021.1.1+Django3.2.3新建一个web项目 教程
  12. 小米pro安装win10系统
  13. iphone模拟器目录
  14. MySQL中update语句的深入分析
  15. java微信扫一扫_java调用微信扫一扫
  16. 鼠标画上去图片旋转360度
  17. 【应用安全】什么是身份和访问管理 (IAM)?
  18. 牛客NC23053月月查华华的手机 题解(指针优化)
  19. mysql ddl过程,MySQL基础教程3-DDL(创建表)
  20. win7 64位 安装tensorflow GPU版本

热门文章

  1. kali中运行apktool出现Input file (***.apk) was not found or was not readable
  2. 《算法撕裂者》系列0 - TopK问题
  3. 《成功的项目管理》案例
  4. 录制的视频有噪音,后期可以降噪吗
  5. idea所有的工具栏都不见了,还有项目目录也不见了
  6. 卷积神经网络中卷积和池化特征图的维度变化(不能被整除问题)
  7. zb薄片怎么往里加厚_ZBRUSH 怎么做穿孔效果?就是那种在比较薄的物体上比如衣服 翅膀 做出破洞的效果?...
  8. dna序列分类数学建模matlab,数学建模常用的分析法及其MATLAB实现
  9. 正则表达式提取工具regularTools
  10. Lora无线终端工作原理及优缺点