文章目录
1. 常见的 IO 模型
在 UNIX 操作系统中,常见的 I/O 模型有以下五种:
1.阻塞 I/O 模型(Blocking I/O)
- 在阻塞 I/O 模型中,应用程序发起一个 I/O 请求后会一直阻塞等待操作完成,直到数据准备好或者超时才返回结果。
- 应用程序在等待 I/O 完成期间会处于阻塞状态,无法执行其他任务。
- 这种模型适用于简单的 I/O 操作,但会造成资源浪费和性能下降。
2.非阻塞 I/O 模型(Non-blocking I/O)
- 在非阻塞 I/O 模型中,应用程序发起一个 I/O 请求后会立即返回,无需等待操作完成。
- 应用程序需要不断轮询或者使用事件通知来检查操作是否完成。
- 这种模型通常适用于需要处理多个连接或者连接数较多的场景,但效率不高。
3.多路复用 I/O 模型(Multiplexing I/O)
- 多路复用 I/O 模型使用操作系统提供的 select、poll 或 epoll 等多路复用机制,允许应用程序同时监视多个 I/O 事件。
- 应用程序可以将多个 I/O 请求注册到一个多路复用器上,然后通过轮询或者阻塞等待多路复用器通知事件的发生。
- 这种模型适用于需要同时处理多个连接的场景,提高了系统的并发性能。
4.信号驱动 I/O 模型(Signal-driven I/O)
- 信号驱动 I/O 模型使用信号机制来实现异步 I/O,应用程序通过向内核注册信号处理函数来处理 I/O 事件。
- 当 I/O 操作完成时,内核会发送一个信号通知应用程序,然后由应用程序在信号处理函数中处理该事件。
- 这种模型相比阻塞 I/O 和非阻塞 I/O 更为灵活,适用于需要处理多个 I/O 事件的场景。
5.异步 I/O 模型(Asynchronous I/O)
- 异步 I/O 模型通过操作系统提供的异步 I/O 接口来实现,应用程序发起一个 I/O 请求后会立即返回,并且在操作完成后会通过回调或事件通知的方式通知应用程序。
- 应用程序无需等待操作完成,可以继续执行其他任务,当操作完成后会触发回调函数或者发送事件通知。
- 这种模型通常适用于需要高并发、高性能的场景,如网络服务器、大规模并行计算等。
2. 阻塞IO(BIO)
在同步阻塞 IO 模型中,应用程序发起 read 调用后会被阻塞,直到内核将数据拷贝到用户空间。
这种模型在客户端连接数量不高的情况下表现良好。但是,当面对大量连接时,传统的 BIO 模型无法有效应对。因此,我们需要一种更高效的 I/O 处理模型来处理更高的并发量。
3. 非阻塞IO(NIO)
非阻塞系统调用允许进程在发起系统调用后继续执行而无需等待内核操作完成。如果数据尚未准备好,系统调用会立即返回一个错误。
进程在返回后可以执行其他任务,然后再次发起系统调用。这种循环进行系统调用的过程被称为轮询。在轮询期间,进程会不断检查内核数据,直到数据准备好。一旦数据准备好,内核会将数据拷贝到进程,然后进行数据处理。
需要注意的是,即使在数据拷贝的过程中,进程仍然处于阻塞状态。
4. IO多路复用
IO多路复用是一种进程预先告知内核的能力,让内核发现进程指定的一个或多个I/O条件就绪后立即通知进程。它能够有效地管理多个I/O操作,提高系统的并发处理能力。
目前,IO复用的主要实现方式有Select、Poll和Epoll。这些方法在内核层面都能够监视多个文件描述符,当其中任何一个描述符就绪时,通知应用程序进行相应的处理。相比于传统的同步阻塞IO模型,IO多路复用可以大幅减少系统调用的次数,提高系统的性能和效率。
5. 信号驱动
首先,允许Socket进行信号驱动IO,并安装一个信号处理函数。当数据准备好时,进程会收到一个SIGIO信号,然后可以在信号处理函数中调用IO操作函数处理数据。这种IO方式的问题在于Linux中信号队列是有限制的,如果超过这个限制,就会导致无法读取数据。
为了优化这个问题,可以考虑使用更为高效的IO多路复用技术,如Select、Poll或Epoll。这些方法能够在内核层面同时监视多个文件描述符,当其中任何一个描述符就绪时,通知应用程序进行相应的处理。相比于信号驱动IO,IO多路复用能够更有效地管理多个IO操作,减少系统调用的次数,并提高系统的性能和效率。
6. 异步IO(AIO)
当用户线程进行了系统调用后,立即就可以开始做其他事情,用户线程不会阻塞。接着,内核会等待数据准备好,并将数据从内核缓冲区拷贝到用户缓冲区。此时,内核会向用户线程发送一个信号,或者调用用户线程注册的回调接口,告知用户线程操作已完成。用户线程可以读取用户缓冲区的数据,并继续执行后续的业务操作。
信号驱动IO和异步IO的主要区别在于:
- 信号驱动IO是由内核告知何时可以开始一个IO操作(数据在内核缓冲区中)。
- 而异步IO则是由内核通知IO操作何时已经完成(数据已经在用户空间中)。
7. BIO,NIO,AIO的区别
1.BIO(Blocking I/O)
- 阻塞 I/O 模型是传统的 I/O 编程模型,在进行 I/O 操作时会阻塞当前线程,直到数据准备就绪或者超时才返回结果。
- BIO 模型适用于连接数较少的场景,每个连接都会创建一个对应的线程来处理,因此对系统资源消耗较大,且效率不高。
- 在 BIO 模型中,通常使用 InputStream 和 OutputStream 来进行阻塞式的数据读写操作。
2.NIO(Non-blocking I/O)
- 非阻塞 I/O 模型是 Java NIO(New I/O)包中引入的一种 I/O 编程模型,它使用了选择器(Selector)和通道(Channel)来实现非阻塞的数据读写操作。
- NIO 模型适用于需要处理多个连接的场景,通过单线程或少量线程同时监视多个通道的 I/O 事件,从而提高了系统的并发性能。
- 在 NIO 模型中,通常使用 ByteBuffer 和 Channel 来进行非阻塞式的数据读写操作。
3.AIO(Asynchronous I/O)
- 异步 I/O 模型是 Java NIO 2 中引入的一种 I/O 编程模型,它使用了异步 I/O 接口和回调机制来实现真正的异步非阻塞 I/O 操作。
- AIO 模型适用于需要高并发、高性能的场景,应用程序在发起 I/O 请求后无需等待操作完成,可以继续执行其他任务,当操作完成后会触发回调函数或者发送事件通知。
- 在 AIO 模型中,通常使用 AsynchronousFileChannel 和 CompletionHandler 来进行异步非阻塞式的数据读写操作。