操作系统中的三种IO模型
阻塞I/O
先来看看阻塞 I/O,当用户程序执行 read,线程会被阻塞
一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回
注意:阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程
过程如下图:
非阻塞 I/O
知道了阻塞 I/O,来看看非阻塞 I/O,非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续下执行
此时应用程序不断轮询内核直到数据准备好
内核将数据拷贝到应用程序缓冲区,read 才可以获取到结果
过程如下图:
注意,这里最后一次 read 调用,获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程
异步IO
举个例子,如果 socket 设置了 O_NONBLOCK 标志,那么就表示使用的是非阻塞 I/O 的方式访问,而不做任何设置的话,默认是阻塞 I/O。
因此,无论 read 和 send 是阻塞 I/O,还是非阻塞 I/O 都是同步调用
因为在 read 调用时,内核将数据从内核空间拷贝到用户空间的过程都是需要等待的,也就是说这个过程是同步的,如果内核实现的拷贝效率不高,read 调用就会在这个同步过程中等待比较长的时间.
真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待
当我们发起 aio_read(异步 I/O)之后,就立即返回,内核自动将数据从内核空间拷贝到用户空间
这个拷贝过程同样是异步的,内核自动完成的
和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作
过程如下图:
理解IO的简单例子
举个你去饭堂吃饭的例子,你好比应用程序,饭堂好比操作系统
阻塞 I/O
你去饭堂吃饭,但是饭堂的菜还没做好,然后你就一直在那里等啊等,等了好长一段时间终于等到饭堂阿姨把菜端了出来(数据准备的过程),但是你还得继续等阿姨把菜(内核空间)打到你的饭盒里(用户空间),经历完这两个过程,你才可以离开。
非阻塞 I/O
你去了饭堂,问阿姨菜做好了没有,阿姨告诉你没,你就离开了,过几十分钟,你又来饭堂问阿姨,阿姨说做好了,于是阿姨帮你把菜打到你的饭盒里,这个过程你是得等待的
异步 I/O
你让饭堂阿姨将菜做好并把菜打到饭盒里后,把饭盒送到你面前,整个过程你都不需要任何等待。
很明显,异步 I/O 比同步 I/O 性能更好,因为异步 I/O 在「内核数据准备好」和「数据从内核空间拷贝到用户空间」这两个过程都不用等待。
BIO AIO NIO有什么区别
什么是IO
IO(Input/Output)是指输入/输出,用于描述计算机与外部设备(如文件、网络、键盘、显示器等)之间的数据交换过程。
计算机在运行过程中,需要与外部世界进行数据的输入和输出。例如,从文件中读取数据、将数据写入到网络传输中、从键盘接收用户的输入等都属于 IO 操作。
需要 IO 的主要原因是:
- 数据持久化:将数据从内存写入到磁盘或其他存储介质中,实现数据的持久化和长期存储。
- 数据交互:与外部设备进行数据的输入和输出,在计算机与用户、计算机与计算机之间传输数据。
- 程序与外部设备的交互:程序需要和外部设备(如键盘、鼠标、显示器、网络等)进行交互,接收用户输入,展示输出结果。
IO 操作是计算机系统中的重要组成部分,它通过数据的输入和输出实现了与外部设备的交互和数据的持久化。在计算机软件开发和系统运行中,IO 是不可或缺的一部分
三个IO有什么区别
简单来说,BIO 就是传统 IO 包,它诞生的最早,但它是同步、阻塞的;
所以在 JDK 1.4 又有了 NIO, NIO 是对 BIO 的改进提供了多路复用的同步非阻塞 IO,而 AIO 是 NIO 的升级,提供了异步非阻塞 IO。
它们的具体区别如下:
- BIO(Blocking I/O):同步阻塞 IO,传统的 java.io 包,它是基于流模型实现的,交互的方式是同步阻塞方式,也就是说在读入输入流或者输出流时,在读写动作完成之前线程会一直阻塞在那里, 它们之间的调用是可靠的线性顺序。它的优点是代码比较简单、直观;缺点是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。
- NIO(Non-blocking I/O):同步非阻塞 IO,Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。
- AIO(Asynchronous I/O):异步非阻塞 IO,Java 1.7 之后引入的包,是 NIO 的升级版本,异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
所以,简单来说:BIO 是同步阻塞 IO;NIO 是同步非阻塞 IO;AIO 是异步非阻塞 IO
关键总结
BIO:每个连接对应一个线程,调用read()
时线程被阻塞,直到数据就绪
NIO:基于多路复用(Selector)实现,通道(Channel)设置为非阻塞模式。单线程通过轮询Selector理多个连接的IO事件
AIO:使用回调或Future机制,IO操作完成后自动触发回调函数
模型 | Java实现 | 操作系统对应机制 | 核心特点 |
同步阻塞 | BIO(每个连接一个线程) |
阻塞调用 | 简单但资源消耗大 |
同步非阻塞 | NIO(Selector多路复用) |
/ 多路复用 | 单线程处理多连接,减少线程开销 |
异步非阻塞 | AIO(回调机制) |
(Windows)、 (Linux) | 真正的异步IO,无需用户态轮询 |