东东
发布于 2022-10-18 / 35 阅读 / 0 评论 / 0 点赞

IO

#IO

概述

IO就是计算机系统与外部设备之间通信的过程,比如说把读写文件,一行一行遍历。
我们在程序发起IO操作,其实操作系统是需要从用户空间(程序)进入到内核空间(操作系统指令),这样才能访问文件。

操作系统内核完成IO操作还包括两个过程:

  • 准备数据阶段:内核等待I/O设备准备好数据
  • 拷贝数据阶段:将数据从内核缓冲区拷贝到用户进程缓冲区

分类

常见的IO有哪些

文件IO:

  • 读取:需要将操作系统内核空间将数据准备好拷贝给应用程序的用户空间;
  • 写入:需要将应用程序的用户空间将数据准备好拷贝给操作系统内核空间

网络IO:

  • 接收网络请求:网络–》网卡–》内核空间–》用户空间
  • 发送网络请求:用户空间–》内核空间–》网卡–》网络

IO流如何进行分类

  • 按照流的方向:输入流(inputStream)和输出流(outputStream);
  • 按照实现功能分:节点流(可以从或向一个特定的地方读写数据,如 FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写, BufferedReader);
  • 按照处理数据的单位: 字节流和字符流。分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的。
    image-1666081599968

字节流如何转为字符流?

  • 字节输入流转字符输入流通过 InputStreamReader 实现,该类的构造函数可以传入 InputStream 对象。
  • 字节输出流转字符输出流通过 OutputStreamWriter 实现,该类的构造函数可以传入 OutputStream 对象。

字符流与字节流的区别?

  • 读写的时候字节流是按字节读写,字符流按字符读写。
  • 字节流适合所有类型文件的数据传输,因为计算机字节(Byte)是电脑中表示信息含义的最小单位。字符流只能够处理纯文本数据,其他类型数据不行,但是字符流处理文本要比字节流处理文本要方便。
  • 在读写文件需要对内容按行处理,比如比较特定字符,处理某一行数据的时候一般会选择字符流。
  • 只是读写文件,和文件内容无关时,一般选择字节流。

IO模型(4种)

  1. 同步阻塞IO(Blocking IO):即BIO,传统的IO模型。
  2. 同步非阻塞IO(Non-blocking IO), 即NIO,默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。
  3. 多路复用IO(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型(Redis单线程为什么速度还那么快,就是因为用了多路复用IO和缓存操作的原因)
  4. 异步IO(Asynchronous IO):即经典的Proactor设计模式,也称为异步非阻塞IO。

BIO(同步阻塞)

image-1666082467247
服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销

NIO(同步非阻塞)

image-1666082436929
同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上;多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

多路复用IO(异步阻塞)

image-1666082984543
服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理(复用同一个线程)

拓展

所谓的I/O复用,就是多个I/O可以复用一个进程。I/O多路复用允许进程同时检查多个fd,以找出其中可执行I/O操作的fd。 系统调用select()和poll()来执行I/O多路复用。

初级版本复用

比如一个进程接受了10000个连接,这个进程每次从头到尾的问一遍这10000个连接:“有I/O事件没?有的话就交给我处理,没有的话我一会再来问一遍。”然后进程就一直从头到尾问这10000个连接。
缺点:如果这10000个连接都没有I/O事件,就会造成CPU的空转,并且效率也很低,不好不好。

升级

select可以同时观察许多流的I/O事件,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流
缺点:因为从select那里仅仅知道了,有I/O事件发生了,但却并不知道是那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。

高级版

epoll可以理解为event poll,不同于忙轮询和无差别轮询,当连接有I/O流事件产生的时候,epoll就会去告诉进程哪个连接有I/O流事件产生,然后进程就去处理这个事件。此时我们对这些流的操作都是有意义的。

AIO(异步非阻塞)

image-1666082896185

同步?异步?阻塞?非阻塞

同步和异步在于请求的方式和请求方的参与

  • 同步:用户请求到结束,都要自己参与,比如用户进程触发IO操作并等待或者轮询去看IO操作是否就绪
  • 异步:用户请求后,就去做其他事情,内核处理好数据再通知我就行了

阻塞与非阻塞,重点在于等消息时候的行为。

  • 阻塞:一直等待,不做其他事情
  • 非阻塞:过程中可以做其他事情