IO模型和NIO、BIO、AIO和reactor模型


发现有时经常搞混BIO和reactor模型的关系。这里记录下。

五种IO模型

阻塞

线程A发起了IO请求,当数据没有返回时,线程A一直被阻塞。

非阻塞

线程A发起了IO请求,当数据没有返回时,可以先返回一个标识,告诉线程A此时没有数据。线程A要想拿到真正的数据,要么就是循环去获得 或者 再开一个线程去监听。
伪代码如下

	while(recfrom() == false) { // 循环等待
	}
	或者
	new Thread(() -> {
		while(recfrom() == false) { // 循环等待
		}
		// 获取数据后,从当前线程传递给A线程
	}).start()

多路复用

就是大名鼎鼎的selector。我们可以用一个线程去管理selector,其他多个进程的I/O都注册到selector上面。当selector监听到有事件发生时,就去通知对应的进程去处理。用Selector的优势在于它可以同时处理多个连接,所以如果处理的连接数不是很多,使用select/epoll的Web Server不一定比使用多线程加阻塞I/O的Web Server性能更好,可能延迟还更大,select/epoll的优势并不是对于单个连接能处理得更快,而是能处理更多的连接
伪代码:

	// 多个进程IO都注册到selector上面。
	while(true) {
		event = select(); // selector线程阻塞监听多个文件描述符
		from 0 to envent : 
			通知对该事件感兴趣的进程;
	}

信号量

涉及用户进程和内核。以对话形式展开:

用户进程:等你有数据了告诉我哈。(于是用户进程就可以处理其他事情)
内核:有数据了
用户进程:哎呀有数据了,那我把数据从 内核态拷贝到用户态吧。(然后用户进程就得到了数据)

实际中使用的较少。

异步

信号量IO是内核告诉我们何时启动IO操作,然后具体的操作由用户来完成
异步IO是内核告诉我们IO操作何时完成。

NIO、BIO、AIO

特指IO在java的技术演进。
BIO对应阻塞IO,NIO对应多路复用IO,AIO对应真正的异步IO。
分别对应java.io包、java.nio包下面的Selector、java.nio包下的AsynchronousServerSocketChannel

reactor模型

是一种设计思想,是一种架构。
Reactor是这样一种模式:它要求主线程只负责监听文件描述符上是否有事件发生,有的话就立刻将该事件通知给工作线程,除此之外,主线程不做任何实质性的工作。
Proactor模式将所有的I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。
比如Netty就用java NIO实现了reactor模型。下面就用此列来讲。

单线程

顾名思义,客户端使用一个线程来收发消息。服务端也用一个线程来处理消息。
服务端的单线程既与客户端建立连接,又去监听各种事件。
在这里插入图片描述
对于并发量较小的业务场景,可以使用单线程模型。但单线程模型不适用于高负载、高并发的场景,
主要原因如下。
(1)一个NIO线程如果同时处理成百上千的链路,则机器在性能上无法满足,即便是NIO线程的CPU负载达到100%,也无法满足海量消息的编码、解码、读取和发送。
(2)如果NIO线程负载过重,那么处理速度将变慢,从而导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,NIO线程就会成为系统的性能瓶颈。
(3)一旦NIO线程发生意外或者进入死循环状态,就会导致整个系统通信模块不可用,从而不能接收和处理外部消息,造成节点故障。

多线程

有一个专门的NIO线程Acceptor用于监听服务端、接收客户端的TCP连接请求。
网络I/O的读、写等操作由一个NIO线程池负责,它包含一个任务队列和多个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送。池子里面一个NIO线程都包含一个select。
在这里插入图片描述
在绝大多数场景下,Reactor多线程模型都可以满足性能需求。但是,在极特殊的应用场景中,一个NIO线程负责监听和处理所有的客户端连接也可能会存在性能问题。例如百万客户端并发连接,或者服务端需要对客户端的握手消息进行安全认证,认证本身消耗性能很大。在这类场景下,单个Acceptor线程可能会存在性能不足的问题,为了解决性能问题,就出现了主从Reactor多线程模型。

主从多线程

即把之前的单线程acceptor,改用线程池。
netty推荐这种用法。实际中,我们对于业务处理,都要单独的再开一个业务处理线程池(也可以对每个小业务 或者 不同的操作划分不同的线程池)。总之就是为了避免阻塞宝贵的IO线程。

本文作者:WKP9418
本文连接:https://blog.csdn.net/qq_43179428/article/details/140582425

相关推荐

  1. Reactor模型

    2024-07-22 11:42:04       54 阅读
  2. Reactor 模式

    2024-07-22 11:42:04       21 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 11:42:04       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 11:42:04       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 11:42:04       45 阅读
  4. Python语言-面向对象

    2024-07-22 11:42:04       55 阅读

热门阅读

  1. 每天一个数据分析题(四百三十六)- 正态分布

    2024-07-22 11:42:04       16 阅读
  2. 使用Event Sourcing模式管理应用状态

    2024-07-22 11:42:04       18 阅读
  3. 从0到1搭建数据中台(4):TiDB的安装和使用

    2024-07-22 11:42:04       16 阅读
  4. Modbus协议了解与简单使用

    2024-07-22 11:42:04       20 阅读
  5. springboot引入kafka

    2024-07-22 11:42:04       14 阅读
  6. web前端 React 框架面试200题(五)

    2024-07-22 11:42:04       14 阅读
  7. MySQL

    2024-07-22 11:42:04       14 阅读
  8. Udp协议

    Udp协议

    2024-07-22 11:42:04      20 阅读
  9. Xcode应用开发:自定义图表的终极指南

    2024-07-22 11:42:04       17 阅读
  10. 7.22 cf

    2024-07-22 11:42:04       19 阅读
  11. 一线大厂前端vue面试题

    2024-07-22 11:42:04       14 阅读
  12. 【MAUI】动态界面

    2024-07-22 11:42:04       21 阅读
  13. 小白C语言基础详解:C 语言的内存管理

    2024-07-22 11:42:04       16 阅读
  14. 等保测评深度探索:揭秘安全合规的幕后英雄

    2024-07-22 11:42:04       18 阅读