IO

170 阅读5分钟

前言

Java IO知识体系

image.png

从计算机结构的角度来解读 I/O

冯诺依曼体系 image.png 从计算机结构的视角来看,I/O描述了计算机系统与外部设备之间通信的过程。

输入设备(如键盘)向计算机输入数据(其他来源 => 计算机程序),输出设备(如显示器)接收计算机输出的数据(计算机程序 => 其他出口)。

从应用程序的角度解读I/O

一个进程的地址空间划分为用户空间(User space)和内核空间。我们平时运行的应用程序都运行在用户空间,只有内核空间才能进行系统态级别的资源有关操作,比如文件管理、进程通信、内存管理等等,并且用户空间的程序不能直接访问内核空间。

当我们在程序中想要进行IO操作时,只能发起系统调用请求操作系统帮忙完成。

从应用程序视角看,我们的应用程序对操作系统的内核发起IO调用(系统调用),操作系统的内核负责执行具体的IO操作。

当应用程序发起I/O调用后,会经历几个步骤:

1.操作系统切换到内核态

2.内核等待I/O设备准备好数据

3.内核将数据从内核空间拷贝到用户空间

常用概念

在了解IO模型清楚之前,我们先要弄清楚几个概念,比如同步&异步,阻塞&非阻塞含义

同步 & 异步

同步:调用方发起一个调用时,在没有得到结果前,该调用不会返回。换句话说,就是由"调用者"主动等待这个结果。

异步:与同步相反,调用发出后直接返回。换句话说,当一个异步调用发出后,"调用者"不会立刻得到结果,而是在调用发出后,"被调用者"通过状态、通知来通知调用者,或通过回调函数来处理这个调用。

同步和异步强调的是消息通信机制。换句话说,是否需要主动去跟踪。

阻塞 & 非阻塞

阻塞:线程发起一个调用时,在调用返回之前,线程会被阻塞,在这个状态下会交出当前CPU的使用权而暂停;也就是调用方会等待调用结果,调用阻塞了调用方的线程。

非阻塞:与阻塞相反,调用会立即返回,避免线程被阻塞。但返回的结果只是被调用方当前状态的值,实际使用时,调用方需要轮询,直到返回结果符合预期(数据准备好)。

阻塞和非阻塞强调的是程序在等待调用结果(消息,返回值)时的状态。

组合

同步阻塞

调用发出后,线程阻塞等待调用结果返回,这期间线程不能做其他事情

同步非阻塞

调用发出后,会立即返回,此时线程可以去做其他事情,但需要不断去询问调用结果是否就绪(比如IO调用,数据是否准备好)

异步阻塞

调用发出后,会立即返回,这期间线程会阻塞,直到"被调用方"告知调用完成。

异步非阻塞

调用发出后,会立即返回,这期间线程可以做其他事情,"调用方"处理完成自行通知或者处理。

BIO(Blocking I/O) 同步阻塞

特点

image.png

image.png

Java早期版本中使用的I/O模型。在BIO模型中,一个Server对接N个客户端,在客户端连接后,为每个客户端都分配一个执行线程。在客户端发起IO操作时,如果操作未完成线程会一直阻塞,直到操作完成(即内核把数据拷贝到用户空间)。

同步体现:

阻塞体现:

优缺点

优点:

  • 简单易用:BIO模型的编程方式相对简单,易于理解和使用
  • 可靠性高:由于阻塞特性,IO操作的结果是可靠的

缺点:

  • 阻塞等待:当一个IO操作被阻塞时,线程会一直等待,无法执行其他任务,导致资源浪费。
  • 并发能力有限:在客户端连接数量不高的情况下是没问题的。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。
  • 由于I/O操作是同步的,客户端的连接需要等待服务器响应,会降低系统的整体性能。

应用场景

适用于连接数比较小且固定的架构,例如文件服务器或小型网站。不适用于高并发场景。

可以使用线程池进行改进,改进之后适合一些简单、低频、短链接的通信场景。

NIO

同步非阻塞IO

image.png

同步非阻塞IO模型中,应用程序会一直发起系统调用查看IO操作是否完成,等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的,直到在内核把数据拷贝到用户空间。

同步体现:

非阻塞体现:

优缺点

优点:

  • 相比于同步阻塞 IO 模型,同步非阻塞 IO 模型确实有了很大改进。通过轮询操作,避免了一直阻塞。

缺点:

  • 应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的。这个时候,I/O 多路复用模型 就上场了

IO多路复用

特点

image.png

多路体现:

复用体现

优缺点
应用场景

AIO 异步IO模型

特点

优缺点

参考