5.NIO零拷贝与传统IO的文件传输性能比较

【README】

1.本文总结自B站《netty-尚硅谷》,很不错;

2.本文部分内容参考自  NIO效率高的原理之零拷贝与直接内存映射 - 腾讯云开发者社区-腾讯云


【1】零拷贝原理

【1.1】传统IO的文件拷贝

 【图解】

  • step1)调用 sys_read系统调用,从用户态进入内核态;借助DMA通道把磁盘驱动数据 读入内核读缓冲区(无需拷贝,因为零拷贝讲的是 无需耗费CPU资源的拷贝,而是DMA拷贝
  • step2)借助CPU把 内核缓冲区数据 读取到用户态缓冲区后,从sys_read系统调用返回,从内核态切换回用户态;(第1次拷贝
  • step3)调用 sys_write 系统调用,从用户态进入内核态;借助CPU把 用户态缓冲区 数据写入 socket 缓冲区(第2次拷贝
  • step4)把 socket 缓冲区数据 借助DMA通道 写入到 网卡驱动(无需cpu参与的拷贝,仅DMA);
  • step5)写入完成后,从内核态返回用户态;

小结: 上述过程中,操作系统底层 有4次用户态与内核态的切换,2次cpu拷贝(DMA拷贝不占CPU,不计入);文件读写(拷贝)性能较低;

补充:

  • 虽然DMA拷贝不占用cpu,但它占用系统总线,一定程度上也会影响cpu性能(但这不是本文重点,可以忽略不计);

【1.2】零拷贝

1)零拷贝 :

  • Linux 在 2.4 版本中,做了一些修改,sendFile() 系统调用 避免了从内核缓冲区拷贝到 Socket buffer 的操作,直接拷贝到协议栈,从而再一次减少了数据拷贝。

2)零拷贝流程图 :

 【图解】

  • step1)调用 sys_read系统调用,从用户态进入内核态,借助DMA通道 把磁盘驱动数据 读入到 内核读缓冲区;(DMA拷贝)
  • step2)接着在内核态中,调用系统调用 sendfile ,cpu把 读缓冲区的数据写出到 socket缓冲区;(第1次CPU拷贝
  • step3)借助DMA通道,把 socket缓冲区数据 写出到 网卡缓冲区;(DMA拷贝)
  • step4)最后从内核态返回到用户态;

【小结】

  • 上述过程中,操作系统底层 有2次用户态与内核态的切换,1次cpu拷贝(非真正零拷贝,因为有1次cpu拷贝)
  • 显然,相比传统IO过程,NIO的零拷贝技术的文件传输性能更高
  • 补充*若网卡驱动支持 gather操作,DMA可以直接把数据从内核读缓冲区直接拷贝到网卡驱动,而无需cpu拷贝(真正实现CPU零拷贝);

NIO零拷贝适用于以下场景:

  • 文件较大,读写较慢,追求速度;
  • JVM内存不足,不能加载太大数据;
  • 内存带宽不够,即存在其他程序或线程存在大量的IO操作,导致带宽本来就小;

【2】代码实现

【2.1】基于传统IO传输文件

注意:字节缓冲 4M (字节缓冲大小会影响传输性能,当然了,一定条件下,缓冲越大越好);

1)服务器:

/*** @Description 传统IO服务器* @author xiao tang* @version 1.0.0* @createTime 2022年08月20日*/
public class OldIOServer {public static void main(String[] args) throws IOException {// 服务器监听端口 7001ServerSocket serverSocket = new ServerSocket(7001);while (true) {// 阻塞式等待客户端请求链接Socket socket = serverSocket.accept();DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());try {byte[] byteArr = new byte[4096];// 读取客户端的数据到字节数组while (dataInputStream.read(byteArr, 0, byteArr.length) != -1) ;} catch (Exception e) {e.printStackTrace();}}}
}

2)客户端:

/*** @Description 传统IO客户端* @author xiao tang* @version 1.0.0* @createTime 2022年08月20日*/
public class OldIOClient {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1", 7001);// 传输 一个 zip文件InputStream inputStream = new FileInputStream("D:\\cmb\\studynote\\netty\\temp\\springboot.zip");DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());byte[] buffer = new byte[4096];long readCount;long total = 0;long startTime = System.currentTimeMillis();while ((readCount = inputStream.read(buffer)) >= 0) {total += readCount;dataOutputStream.write(buffer);}long cost = System.currentTimeMillis() - startTime;System.out.println("发送总字节数 " + total + ", 耗时 = " + cost);// 关闭资源dataOutputStream.close();socket.close();inputStream.close();}
}

3)效果:

发送总字节数 4491230, 耗时 = 50


【2.2】基于NIO零拷贝传输文件

注意:字节缓冲 4M (字节缓冲大小会影响传输性能,当然了,一定条件下,缓冲越大越好);

1)服务器:

/*** @Description nio实现零拷贝服务器* @author xiao tang* @version 1.0.0* @createTime 2022年08月20日*/
public class ZeroCopyNIOServer {public static void main(String[] args) throws IOException {// 服务器套接字通道ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 绑定端口serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1", 7001));ByteBuffer buffer = ByteBuffer.allocate(4096);while (true) {// 等待客户端连接SocketChannel socketChannel = serverSocketChannel.accept();// 读取数据while (socketChannel.read(buffer) != -1) {// 缓冲倒带, 设置 position=0, mark作废buffer.rewind();}}}
}

2)客户端:

/*** @Description nio实现零拷贝服务器* @author xiao tang* @version 1.0.0* @createTime 2022年08月20日*/
public class ZeroCopyNIOClient {public static void main(String[] args) throws IOException {SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 7001));FileChannel fileChannel = new FileInputStream("D:\\cmb\\studynote\\netty\\temp\\springboot.zip").getChannel();long startTime = System.currentTimeMillis();// 在 linux 下,一次调用 transferTo 方法就可以完成传输// 在 window下,一次调用 transferTo 只能发送 8M,如果大于8M,则需要分段传输文件// transferTo 底层就用到了 零拷贝long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);long cost = System.currentTimeMillis() - startTime;System.out.println("客户端发送数据成功,耗时= " + cost + ", 传输的字节总数 = " + transferCount);}
}

 3)效果:

客户端发送数据成功,耗时= 10, 传输的字节总数 = 4491230

4)补充: 关于 FileChannel.transferTo 方法 

  • 在 linux 下,一次调用 FileChannel.transferTo 方法就可以完成传输;
  • 在 window下,一次调用 transferTo 只能发送 8M,如果大于8M,则需要分段传输文件;
  • transferTo 底层就用到了 零拷贝;

5)transferTo方法底层使用的是 sendfile 系统调用(零拷贝)

  • 该系统调用 实现了数据直接从内核的读缓冲区传输到套接字缓冲区,避免了用户态(User-space) 与内核态(Kernel-space) 之间的数据拷贝。

【4】性能比较

【表】传统IO与NIO零拷贝传输性能对比 (文件大小 4M

Java IO类型

传输耗时

备注

传统IO

50ms

NIO零拷贝

10ms

性能更优

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

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

相关文章

二进制漏洞利用与挖掘_二进制各种漏洞原理实战分析总结

本部分将对常见的二进制漏洞做系统分析,方便在漏洞挖掘过程中定位识别是什么类型漏洞,工欲善其事,必先利其器。0x01栈溢出漏洞原理栈溢出漏洞属于缓冲区漏洞的一种,实例如下:编译后使用windbg运行直接运行到了地址0x41…

Oracle入门(十四H)之良好的编程实践

一、为什么要学习它 好的编程实践是技巧,可以按照创建最好的代码可能。 编程实践涵盖了一切从代码更多可以用更快的速度创建代码性能。 软件工程团队通常会遵循风格指导让团队中的每个人使用相同的技术。 这使它更容易阅读和修改编写的代码其他。二、编程实践已经学…

微软.NET 正式劈腿成功,横跨所有平台

.NET官方博客宣布了《Announcing .NET Core RC2 and .NET Core SDK Preview 1》,正式如期发布了.NET Core RC2, 现在可以放心的基于.NET Core 构建 ASP.NET Core, console apps 和 class libraries for Windows, OS X and Linux。这里贴张图表达下他们之间的关系: …

2.BIO与NIO区别

【README】 1.本文总结自B站《netty-尚硅谷》,很不错;2.本文介绍 BIO, NIO的知识;【1】BIO(传统java IO模型) 1)BIO-Blocking IO:同步阻塞,服务器实现模式为一个连接一…

k8s往secret里导入证书_K8S之Secret

简介secret顾名思义,用于存储一些敏感的需要加密的数据。这些数据可能是要保存在pod的定义文件或者docker的镜像中。把这些数据通过加密的方式存放到secrets对象中,可以降低信息泄露的风险。在secret中存储的数据都需要通过base64进行转换加密后存放。创…

Oracle入门(十四G)之PL / SQL中检索数据

一、PL / SQL中检索数据 (1)PL / SQL中的SQL语句可以在PL / SQL中使用以下几种SQL语句:•SELECT从数据库检索数据。•DML语句,例如INSERT,UPDATE和DELETE,以更改数据库中的行。•事务控制语句,例…

.NET Core 1.0 CentOS7 尝试

昨天宣布 ASP.NET Core RC2,据说差不多稳定了,以后不会有大改了。 参考:https://blogs.msdn.microsoft.com/webdev/2016/05/16/announcing-asp-net-core-rc2/ 一、环境装备 等待很久了,高兴之余昨晚安装一个CentOS系统,版本如下&a…

6.netty线程模型-Reactor

【README】 1..本文部分内容翻译自: [Netty] Nettys thread model and simple usage 2.netty模型是以 Reactor模式为基础的,具体的,netty使用的是 主从Reactor多线程模型; 3.先介绍了 Reactor线程模型;后介绍了 Ne…

python mac读取 文件属性_从Python获取和设置mac文件和文件夹查找器标签

macfile模块是^{}模块的一部分,在"2006-11-20 0.2.0"中被重命名为mactypes使用此模块,以下两个函数可用于获取和设置appscript 1.0版的查找器标签:from appscript import appfrom mactypes import File as MacFile# Note these lab…

Oracle入门(十四.1)之PL / SQL简介

一、PL / SQL描述程序语言扩展到SQL: •允许将基本程序逻辑和控制流与SQL语句组合在一起。 •是Oracle专有编程语言。- 它只能用于Oracle数据库或工具。二、程序语言扩展到SQL•是一种程序语言。 - 当遵循一系列指令时会产生结果。 •是3GL(第三代编程语…

构建高性能.NET应用之配置高可用IIS服务器-第三篇 IIS中三个核心组件的讲解(上)

今天的文章的比较的容易,主要讲述IIS中三个比较重要的组件:协议监听者(Protocol Listeners),WWW服务(World Wide Web Publishing Service)和WAS(Windows Process Activation Service),理解这三个组件的功能,是理解IIS…

7.netty服务器中提交任务到NioEventLoop(Nio事件循环执行线程)

【README】 1.本文总结自 B站 《尚硅谷-netty》; 2.NioEventLoop实际上是一个提交到线程池的Runnable任务,在while无限循环中运行 taskQueue中的任务(串行); 【1】提交任务到NioEventLoop 1)NioEventLoop&#xff1…

Oracle入门(十四.2)之PL / SQL的好处

一、PL / SQL的好处在Oracle数据库中使用PL / SQL编程语言有很多好处。 1.将过程构造与SQL集成 2.模块化程序开发 3.改进的性能 4.与Oracle工具集成 5.便携性6.异常处理二、优点 优点1:使用SQL集成程序化结构PL / SQL的首要优势是程序结构与SQL的集成。 SQL是一种非…

炒菜机器人的弊端_机器人炒菜真不是你想的那样!

7月8日下午,爱餐全产业链模式发布会在张家口进行,会上,张家口文旅投集团与上海爱餐机器人有限公司签订了3000台智能机器人设备合作协议,这些机器人可是身手不凡,清一色的都是会厨艺的炒菜机器人,未来他们还…

构建高性能.NET应用之配置高可用IIS服务器-第四篇 IIS常见问题之:工作进程回收机制(上)

通过三篇文章的普及,相信大家对IIS应该有了一个基本的了解。那么从本篇文章开始,我们就开始进入IIS一些比较实际的话题:如何配置IIS,使得其性能尽可能的高。 我们在本篇中主要讲述的就是“工作进程回收机制”,下面我们…

8.基于netty实现群聊,心跳检测

【README】 1.本文总结自B站《netty-尚硅谷》,很不错; 2.本文po出了 Unpooled创建缓冲区的 代码示例; 3.本文示例代码基于netty实现以下功能: 群聊客户端及服务器;心跳检测;【1】Unpooled创建缓冲区 U…

Oracle入门(十四.3)之创建PL / SQL块

一、PL / SQL块结构 一个PL / SQL块由三部分组成。PL / SQL块结构部分二、PL / SQL编译器用高级编程语言(C,Java,PL / SQL等)编写的每个程序都必须经过检查并转换为二进制代码(1和0),然后才能执…

[.NET Core].NET Core R2安装及示例教程

前言 前几天.NET Core发布了.NET Core 1.0.1 R2 预览版,之前想着有时间尝试下.NET Core。由于各种原因,就没有初试。刚好,前几天看到.NET Core发布新版本了,决定要去一探究竟。于是乎,就立马去官网查找相关的信息&…

Oracle入门(十四.4)之在PL / SQL中使用变量

一、变量的使用 (1)使用变量的原因•临时存储数据 •储存值的操作 •可重用性(2)处理PL / SQL中的变量变量是: •在声明部分声明并初始化 •在可执行部分中使用并分配新值 变量可以是: •作为参数传递给PL …

dismiss的词组_法律英语常用词必记:Dismiss

Dismiss英[dɪsmɪs] 美[dɪsmɪs]【英文释义】v.to refuse to give further hearing to a case in court. If a judge dismisses a court case, they officially decide that the case should not continue【中文释义】v. (1)解雇;免职;开除(2)驳回(起诉…