1、Stream 与 Channel

2、IO 模型

当调用一次 channel.read或 stream.read后,会由用户态切换至操作系统内核态来完成真正数据读取,而读取又分为两个阶段,分别为:


(相关资料图)

根据 UNIX 网络编程 - 卷 I,IO 模型主要有以下几种

阻塞 IO

非阻塞IO

多路复用

Java 中通过 Selector 实现多路复用

多路复用与阻塞IO的区别

异步IO

3、零拷贝

零拷贝指的是数据无需拷贝到 JVM 内存中,同时具有以下三个优点

传统 IO 问题

传统的 IO 将一个文件通过 socket 写出

File f = new File("helloword/data.txt");RandomAccessFile file = new RandomAccessFile(file, "r");byte[] buf = new byte[(int)f.length()];file.read(buf);Socket socket = ...;socket.getOutputStream().write(buf);

内部工作流如下

可以看到中间环节较多,java 的 IO 实际不是物理设备级别的读写,而是缓存的复制,底层的真正读写是操作系统来完成的

NIO优化

通过 DirectByteBuf

大部分步骤与优化前相同,唯有一点:Java 可以使用 DirectByteBuffer 将堆外内存映射到 JVM 内存中来直接访问使用

进一步优化 1

以下两种方式都是零拷贝,即无需将数据拷贝到用户缓冲区中(JVM 内存中)

底层采用了 linux 2.1后提供的 sendFile方法,Java 中对应着两个 channel 调用 transferTo/transferFrom方法拷贝数据

这种方法下

进一步优化 2

linux 2.4对上述方法再次进行了优化

整个过程仅只发生了 1 次用户态与内核态的切换,数据拷贝了 2 次

4、AIO

AIO 用来解决数据复制阶段的阻塞问题

异步模型需要底层操作系统(Kernel)提供支持

  • Windows 系统通过 IOCP 实现了真正的异步 IO
  • Linux 系统异步 IO 在 2.6 版本引入,但其底层实现还是用多路复用模拟了异步 IO,性能没有优势

本文由传智教育博学谷教研团队发布。

如果本文对您有帮助,欢迎关注点赞;如果您有任何建议也可留言评论私信,您的支持是我坚持创作的动力。

转载请注明出处!

推荐内容