NIO与零拷贝和AIO
零拷贝基本介绍
1.零拷贝是网络编程的关键,很多性能优化都离不开。
2.在 Java 程序中,常用的零拷贝有 mmap(内存映射)和 sendFile。那么,他们在 OS 里,到底是怎么样的一个的设计?我们分析 mmap 和 sendFile 这两个零拷贝
3.另外我们看下 NIO 中如何使用零拷贝
传统 IO 数据读写
Java 传统 IO 和网络编程的一段代码
File file = new File("test.txt");
RandomAccessFile raf = new RandomAccessFile(file, "rw");byte[] arr = new byte[(int) file.length()];
raf.read(arr);Socket socket = new ServerSocket(8080).accept();
socket.getOutputStream().write(arr);
分析在以上传统的IO数据读写中,发生了多少次文件的拷贝以及用户态和内核态的状态切换。
传统 IO 模型
DMA:direct memory access 直接内存拷贝(不使用 CPU)
可以看到图中上面一部分代表状态的切换,user context代表用户态,kernel context代表内核态。
从整个模型来看,他首先把硬件hard disk上的数据进行DMA拷贝,也就是在读的过程中,我们用了read方法,它首先把硬盘上的数据经过DMA拷贝,拷贝到内核buffer,然后再用CPU拷贝,拷贝到我们的用户buffer,数据在用户buffer中进行修改。修改完之后,再用CPU拷贝,拷贝到socketbuffer,然后再用DMA拷贝,拷贝到协议栈protocol engine
传统IO经历了4次拷贝,3次状态切换。
mmap 优化(memory map内存映射)
1.mmap 通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。这样,在进行网络传输时,就可以减少内核空间到用户空间的拷贝次数。如下图
2.mmap 示意图
如果使用了内存映射技术,第一次DMA拷贝还是有的,即DMA将硬件中的内容拷贝到内核,由于kernel buffer和user buffer可以共享数据,此时这个地方就不会发生CPU拷贝,数据可以直接在内核缓冲进行修改。修改完了之后再通过CPU拷贝到socket buffer.然后再通过socket buffer经过DMA拷贝到协议栈。
在mmap优化之后,状态切换次数没有改变,仍是3次,拷贝次数变为3次。
sendFile 优化
Linux2.1 版本提供了 sendFile 函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 SocketBuffer,同时,由于和用户态完全无关,就减少了一次上下文切换
示意图和小结
第一次仍然是通过DMA拷贝将硬件数据转移到内核buffer,然后经过CPU拷贝到socketbuffer,然后再通过DMA拷贝到协议栈
由4次拷贝减少到到3次,状态切换变为2次。
3.提示:零拷贝从操作系统角度,是没有 cpu 拷贝
不可能数据读取不经过内核
4.Linux在2.4 版本中,做了一些修改,避免了从内核缓冲区拷贝到 Socketbuffer 的操作,直接拷贝到协议栈,从而再一次减少了数据拷贝。具体如下图和小结:
先经过DMA拷贝到内核buffer,此时socket buffer变成灰色,指的是内核buffer可以直接进行DMA拷贝到协议栈。当然,很少的数据还是可能会有一次CPU拷贝,从内核buffer到socket buffer,但是数据量很少,比如kernel buffer的长度,size,消耗低,可以忽略。
5.这里其实有一次 cpu 拷贝 kernel buffer -> socket buffer 但是,拷贝的信息很少,比如 lenght、offset 消耗低,可以忽略
所以由4次拷贝变为2次。CPU拷贝变为0次。由3次上下文切换变为2次。
零拷贝的再次理解
1.我们说零拷贝,是从操作系统的角度来说的。因为内核缓冲区之间,没有数据是重复的(只有 kernel buffer 有一份数据,而前面的方法中从kernel buffer经过CPU拷贝到socket buffer,有两份数据)。
2.零拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势,例如更少的上下文切换,更少的 CPU 缓存伪共享以及无 CPU 校验和计算。
mmap 和 sendFile 的区别
1.mmap 适合小数据量读写,sendFile 适合大文件传输。
2.mmap 需要 4 次上下文切换,3 次数据拷贝;sendFile 需要 3 次上下文切换,最少 2 次数据拷贝。
3.sendFile 可以利用 DMA 方式,减少 CPU 拷贝,mmap 则不能(必须从内核拷贝到 Socket
NIO 零拷贝案例
案例要求:
1.使用传统的 IO 方法传递一个大文件
2.使用 NIO 零拷贝方式传递(transferTo)一个大文件
3.看看两种传递方式耗时时间分别是多少
NewIOServer.javapackage com.atguigu.nio.zerocopy;import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;//服务器
public class NewIOServer {public static void main(String[] args) throws Exception {InetSocketAddress address = new InetSocketAddress(7001);ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();ServerSocket serverSocket = serverSocketChannel.socket();serverSocket.bind(address);//创建bufferByteBuffer byteBuffer = ByteBuffer.allocate(4096);while (true) {SocketChannel socketChannel = serverSocketChannel.accept();int readcount = 0;while (-1 != readcount) {try {readcount = socketChannel.read(byteBuffer);} catch (Exception ex) {// ex.printStackTrace();break;}//byteBuffer.rewind(); //倒带 position = 0 mark 作废}}}
}
NewIOClient.javapackage com.atguigu.nio.zerocopy;import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;public class NewIOClient {public static void main(String[] args) throws Exception {SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 7001));String filename = "protoc-3.6.1-win32.zip";//得到一个文件channelFileChannel fileChannel = new FileInputStream(filename).getChannel();//准备发送long startTime = System.currentTimeMillis();//在 linux 下一个 transferTo 方法就可以完成传输//在 windows 下一次调用 transferTo 只能发送 8m, 就需要分段传输文件,而且要主要//传输时的位置=》课后思考...//transferTo 底层使用到零拷贝long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);System.out.println("发送的总的字节数 = " + transferCount + " 耗时: " + (System.currentTimeMillis() - startTime));//关闭fileChannel.close();}
}
Java AIO 基本介绍
JDK7 引入了 AsynchronousI/O,即 AIO。在进行 I/O 编程中,常用到两种模式:Reactor 和 Proactor。Java 的 NIO 就是 Reactor,当有事件触发时,服务器端得到通知,进行相应的处理
AIO 即 NIO2.0,叫做异步不阻塞的 IO。AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用
目前 AIO 还没有广泛应用,Netty 也是基于 NIO,而不是 AIO,因此我们就不详解 AIO 了,有兴趣的同学可以参考《Java新一代网络编程模型AIO原理及Linux系统AIO介绍》
BIO、NIO、AIO 对比表
BIO | NIO | AIO | |
---|---|---|---|
IO模型 | 同步阻塞 | 同步非阻塞(多路复用) | 异步非阻塞 |
编程难度 | 简单 | 复杂 | 复杂 |
可靠性 | 差 | 好 | 好 |
吞吐量 | 低 | 高 | 高 |
举例说明
1.同步阻塞:到理发店理发,就一直等理发师,直到轮到自己理发。
2.同步非阻塞:到理发店理发,发现前面有其它人理发,给理发师说下,先干其他事情,一会过来看是否轮到自己.
3.异步非阻塞:给理发师打电话,让理发师上门服务,自己干其它事情,理发师自己来家给你理发
NIO与零拷贝和AIO相关推荐
- NIO效率高的原理之零拷贝与直接内存映射
前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,点击查看. 这篇博客将针对第三个原因,进行更详细的讲解. 首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并 ...
- NIO、BIO编程模型与零拷贝
Java IO模型 Java共支持3种网络编程模型/IO模式:BIO.NIO.AI BIO 同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进 ...
- jvm 堆外内存_NIO效率高的原理之零拷贝与直接内存映射
更多内容,欢迎关注微信公众号:全菜工程师小辉~ 前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理. 这篇博客将针对第三个原因,进行更详细的讲 ...
- 【Netty】零拷贝案例 ( transferTo | transferFrom )
文章目录 一. 案例需求 二. 传统 BIO 拷贝案例 三. 零拷贝案例 服务器端 四. 零拷贝案例 客户端 五. 零拷贝案例 运行与分析 一. 案例需求 给出两个案例 , 一个是 使用普通的 BIO ...
- 【Netty】Netty零拷贝原理
前言 理解零拷贝 零拷贝是Netty的重要特性之一,而究竟什么是零拷贝呢? WIKI中对其有如下定义: "Zero-copy" describes computer operati ...
- 彻底搞懂Netty高性能之零拷贝
作为Java网络编程学习者,不仅要知道NIO,还一定要学习Mina和Netty这两个优秀的网络框架.作为上一篇NIO效率高的原理之零拷贝与直接内存映射的补充,本文将针对Netty的零拷贝特性进行详细分 ...
- 四十七、Netty零拷贝
零拷贝的定义 Zero-copy, 就是在操作数据时, 不需要将数据 buffer 从一个内存区域拷贝到另一个内存区域. 因为少了一次内存的拷贝, 因此 CPU 的效率就得到的提升. 在 OS 层面上 ...
- java基础巩固-宇宙第一AiYWM:为了维持生计,四大基础之OS_Part_2整起~IO们那些事【包括五种IO模型:(BIO、NIO、IO多路复用、信号驱动、AIO);零拷贝、事件处理及并发等模型】
PART0.前情提要: 通常用户进程的一个完整的IO分为两个阶段(IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者!):[操作系统和驱动程序运行在内核空间,应用程序运行在用户空间, ...
- 从BIO到NIO、AIO和零拷贝
文章目录 从BIO到NIO.AIO和零拷贝 BIO NIO AIO 零拷贝 结论 从BIO到NIO.AIO和零拷贝 在JAVA的网络编程方面,BIO.NIO.AIO和零拷贝是我们必须掌握的技术,它们分 ...
最新文章
- 编程 25 年后,现实将我打回菜鸟程序员的起点
- curl比较有用的参数
- c语言pause()函数(让进程暂停直到信号出现)
- python习题集整理汇总
- 我的世界java版使用剑_我的世界:JAVA版藏“私货”内置绝世好剑与神功,你玩的版本有吗...
- MyBatis 多表关联相同字段的解决方案
- Delphi 的绘图功能[5] - 获取 Canvas 对象
- 计算机二级与c语言有什么关系,计算机二级c和c++区别?
- 人脸识别常用开源数据集大全
- 什么是TTL电平和cmos电平?ttl电平和cmos电平的区别是什么?
- Win10预览版之BUG
- 01【计算机基础、Java概述】
- js修改div标签中的内容
- php汉字占几个字节,php一个汉字几个字节
- sin和cos的爱恋
- Mahalanobis距离(马氏距离)的“哲学”解释
- Remote Dictionary Server(Redis)——基于 KV 结构的作为 Cache 使用的 NoSQL 数据库管理系统
- 从未在一起更让人遗憾_从未在一起和在一起后分开,哪个更遗憾?
- 1个系统节拍 c语言_【菜鸡C语言】菜鸡鼓起勇气用Dev-c++打起节奏来了
- Spring 的自动装配
热门文章
- 原来微信可以自定义!把这些功能全关闭后 真清爽!
- 章泽天卸任刘强东旗下一公司董事
- 苹果罕见人事大调整:多个项目被迫暂停 员工“惊慌失措”
- 拳王虚拟项目公社:自动化的虚拟资源产品,唱歌教程赚地盆满钵满
- C语言结构体对齐[转]
- mysql5.6 load_MySQL 5.6 dump/load buffer pool实验
- es创建索引设置字段不分词_java整合es指定字段不分词搜索
- BMP图片读写接口函数
- linux下CPP的认识
- 【Elasticsearch】 es watcher 视频 笔记