本文介绍操作系统I/O工作原理,Java I/O设计,基本使用,开源项目中实现高性能I/O常见方法和实现,彻底搞懂高性能I/O之道
基础概念
在介绍I/O原理之前,先重温几个基础概念:
(1) 操作系统与内核
操作系统:管理计算机硬件与软件资源的系统软件
内核:操作系统的核心软件,负责管理系统的进程、内存、设备驱动程序、文件和网络系统等等,为应用程序提供对计算机硬件的安全访问服务
2 内核空间和用户空间
为了避免用户进程直接操作内核,保证内核安全,操作系统将内存寻址空间划分为两部分:
内核空间(Kernel-space),供内核程序使用
用户空间(User-space),供用户进程使用
为了安全,内核空间和用户空间是隔离的,即使用户的程序崩溃了,内核也不受影响
3 数据流
计算机中的数据是基于随着时间变换高低电压信号传输的,这些数据信号连续不断,有着固定的传输方向,类似水管中水的流动,因此抽象数据流(I/O流)的概念:指一组有顺序的、有起点和终点的字节集合,
抽象出数据流的作用:实现程序逻辑与底层硬件解耦,通过引入数据流作为程序与硬件设备之间的抽象层,面向通用的数据流输入输出接口编程,而不是具体硬件特性,程序和底层硬件可以独立灵活替换和扩展
I/O 工作原理
1 磁盘I/O
典型I/O读写磁盘工作原理如下:
tips: DMA:全称叫直接内存存取(Direct Memory Access),是一种允许外围设备(硬件子系统)直接访问系统主内存的机制。基于 DMA 访问方式,系统主内存与硬件设备的数据传输可以省去CPU 的全程调度
值得注意的是:
读写操作基于系统调用实现
读写操作经过用户缓冲区,内核缓冲区,应用进程并不能直接操作磁盘
应用进程读操作时需阻塞直到读取到数据
2 网络I/O
这里先以最经典的阻塞式I/O模型介绍:
tips:recvfrom,经socket接收数据的函数
值得注意的是:
网络I/O读写操作经过用户缓冲区,Sokcet缓冲区
服务端线程在从调用recvfrom开始到它返回有数据报准备好这段时间是阻塞的,recvfrom返回成功后,线程开始处理数据报
Java I/O设计
1 I/O分类
Java中对数据流进行具体化和实现,关于Java数据流一般关注以下几个点:
(1) 流的方向
从外部到程序,称为输入流;从程序到外部,称为输出流
(2) 流的数据单位
程序以字节作为最小读写数据单元,称为字节流,以字符作为最小读写数据单元,称为字符流
(3) 流的功能角色
从/向一个特定的IO设备(如磁盘,网络)或者存储对象(如内存数组)读/写数据的流,称为节点流;
对一个已有流进行连接和封装,通过封装后的流来实现数据的读/写功能,称为处理流(或称为过滤流);
2 I/O操作接口
java.io包下有一堆I/O操作类,初学时看了容易搞不懂,其实仔细观察其中还是有规律:
这些I/O操作类都是在继承4个基本抽象流的基础上,要么是节点流,要么是处理流
2.1 四个基本抽象流
java.io包中包含了流式I/O所需要的所有类,java.io包中有四个基本抽象流,分别处理字节流和字符流:
InputStream
OutputStream
Reader
Writer
2.2 节点流
节点流I/O类名由节点流类型 + 抽象流类型组成,常见节点类型有:
File文件
Piped 进程内线程通信管道
ByteArray / CharArray (字节数组 / 字符数组)
StringBuffer / String (字符串缓冲区 / 字符串)
节点流的创建通常是在构造函数传入数据源,例如:
FileReader reader = new FileReader(new File("file.txt"));
FileWriter writer = new FileWriter(new File("file.txt"));
2.3 处理流