大型网站建站,windows2012系统怎么建设网站,罗湖商城网站建设哪家公司便宜点,宿迁北京网站建设【README】
1.本文总结自B站《netty-尚硅谷》#xff0c;很不错#xff1b;
2.本文部分内容参考自 NIO效率高的原理之零拷贝与直接内存映射 - 腾讯云开发者社区-腾讯云 【1】零拷贝原理
【1.1】传统IO的文件拷贝 【图解】
step1#xff09;调用 sys_read系统调用#…【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参与的拷贝仅DMAstep5写入完成后从内核态返回用户态
小结 上述过程中操作系统底层 有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) {// 缓冲倒带 设置 position0 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 底层就用到了 零拷贝
5transferTo方法底层使用的是 sendfile 系统调用零拷贝
该系统调用 实现了数据直接从内核的读缓冲区传输到套接字缓冲区避免了用户态(User-space) 与内核态(Kernel-space) 之间的数据拷贝。【4】性能比较
【表】传统IO与NIO零拷贝传输性能对比 文件大小 4M Java IO类型 传输耗时 备注 传统IO 50ms NIO零拷贝 10ms 性能更优