在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,Proactor用于异步I/O操作。
Reactor模式称之为响应器模式,通常用于NIO非阻塞IO的网络通信框架中。
文章相关视频讲解:
C/C++ Linux后台服务器开发高级架构师免费学习链接:C/C++Linux服务器开发高级架构师/Linux后台架构师-学习视频
几个概念:
- 什么是阻塞和非阻塞?
阻塞和非阻塞是针对于进程在访问数据时,根据IO操作的就绪状态而采取的不同方式,简单来说是一种读取或写入操作函数的实现方式,阻塞方式下读取或写入函数将一直等待。非阻塞方式下,读取和写入函数会立即返回一个状态值。
- 什么是同步和异步?
同步和异步是针对应用程序和内核的交互而言的,同步是指用户进程触发IO操作并等待或轮询的查看IO操作是否就绪,异步是指用户进程触发IO操作以后便开始做自己的事情,当IO操作完成时会得到通知,换句话说异步的特点就是通知。
- 什么是IO模型?
一般而言,IO模型可以分为四种:同步阻塞、同步非阻塞、异步阻塞、异步非阻塞
- 同步阻塞IO是指用户进程在发起一个IO操作后必须等待IO操作完成,只有当真正完成了IO操作后用户进程才能运行。
- 同步非阻塞IO是指用户进程发起一个IO操作后立即返回,程序也就可以做其他事情。但是用户进程需要不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。
- 异步阻塞IO是指应用发起一个IO操作后不必等待内核IO操作的完成,内核完成IO操作后会通知应用程序。这其实是同步和异步最关键的区别,同步必须等待或主动询问IO操作是否完成,那么为什么说是阻塞呢?因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,采用select函数的好处在于可以同时监听多个文件句柄,从而提高系统的并发性。
- 异步非阻塞IO是指用户进程只需要发起一个IO操作后立即返回,等IO操作真正完成后,应用系统会得到IO操作完成的通知,此时用户进程只需要对数据进行处理即可,不需要进行实际的IO读写操作,因为真正的IO读写操作已经由内核完成。
NIO非阻塞IO处理流程
非阻塞IO处理流程
- Acceptor注册Selector并监听accept事件
- 当客户端连接后会触发accept事件
- 服务器构建对应的Channel并在其上注册Selector,用于监听读写事件。
- 当发生读写事件后进行相应的读写处理
NIO非阻塞IO的优点在于性能瓶颈高,缺点在于模型复杂、编码复杂、需要处理半包问题。简单来说非阻塞IO不需要一个连接建立一个线程,它可以在一个线程中处理所有的连接。但是由于是非阻塞的,所以应用无法知道什么时候消息读完了,也就会存在半包的问题。
什么是半包问题呢?
TCP/IP在发送消息时可能会拆包,拆包会导致接收端无法得知什么时候接收到的数据是一个完整的数据。在BIO阻塞性IO模型中,当读取步到数据后会阻塞,而在NIO非阻塞IO中则不会,所以需要自行进行处理。比如以换行符作为判断依据,或者是定长消息发送,或者是自定义协议等。
什么是Reactor模式?
Reactor模式是处理并发I/O常见的一种模式,用于同步I/O,其中心思想是将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程阻塞在多路复用器上,一旦有I/O事件到来或是准备就绪,多路复用器将返回并将相应I/O事件分发到对应的处理器中。
Reactor是一种事件驱动机制,和普通函数调用不同的是应用程序不是主动的调用某个API来完成处理,恰恰相反的是Reactor逆置了事件处理流程,应用程序需提供相应的接口并注册到Reactor上,如果有相应的事件发生,Reactor将主动调用应用程序注册的接口(回调函数)。
The reactor design pattern is an event handling pattern for handling service requests delivered concurrently by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to associated request handlers.
Reactor
Reactor模式称为反应器模式或应答者模式,是基于事件驱动的设计模式,拥有一个或多个并发输入源,有一个服务处理器和多个请求处理器,服务处理器会同步的将输入的请求事件以多路复用的方式分发给相应的请求处理器。
Reactor设计模式是一种为处理并发服务请求,并将请求提交到一个或多个服务处理程序的事件设计模式。当客户端请求抵达后,服务处理程序使用多路分配策略,由一个非阻塞的线程来接收所有请求,然后将请求派发到相关的工作线程并进行处理的过程。
在事件驱动的应用中,将一个或多个客户端的请求分离和调度给应用程序,同步有序地接收并处理多个服务请求。对于高并发系统经常会使用到Reactor模式,用来替代常用的多线程处理方式以节省系统资源并提高系统的吞吐量。
关于C/C++ Linux后端开发网络底层原理知识 点击