Linux网络编程 | 事件处理模式:Reactor模式、Proactor模式


随着网络设计模式的兴起,Reactor和Proactor事件处理模式应运而生。同步I/O模型通常用于实现Proactor模式,异步I/O模型通常用于实现Proactor模式

Reactor模式

Reactor模式要求主线程(I/O处理单元)只负责监听文件描述符上是否有事件就绪,如果有则将该就绪事件通知给工作线程(逻辑单元)。除此之外主线程不会进行其他实质性的工作,读写数据、接收新连接、业务逻辑处理全部在工作线程中完成

这里以epoll为例子,使用同步I/O模型实现的Reactor模式的工作流程如下:

  1. 主线程往epoll内核事件表中注册socket上的读就绪事件
  2. 主线程调用epoll_wait开始对socket的读事件进行监控
  3. 如果socket读就绪,epoll_wait会通知主线程,主线程则将socket可读事件放入请求队列中。
  4. 请求队列上某个休眠的工作线程被唤醒,此时会从socket中读取数据,并且处理用户请求,然后后往epoll内核事件表中注册该socket的写就绪事件。
  5. 主线程继续调用epoll_wait对socket的写事件进行监控
  6. 当socket写就绪时,epoll_wait会通知主线程,主线程则将socket可写事件放入请求队列中。
  7. 请求队列上某个休眠的工作线程被唤醒,将服务器处理客户请求的结果写入到socket中
    在这里插入图片描述
    在这种模式下,工作线程会通过判断epoll_wait中的就绪事件类型来决定如何处理事件,所以并不会区分工作线程的种类。

Proactor模式

Proactor模式则是将所有的I/O操作全部交给主线程和内核处理,工作线程仅仅负责业务逻辑。

这里以aio为例子,使用异步I/O模型实现的Reactor模式的工作流程如下:

  1. 主线程调用aio_read函数向内核注册socket上的读就绪事件,并且告诉内核用户读缓冲区的位置,以及注册读操作完成时通知应用程序的信号。
  2. I/O事件交给内核进行异步处理,此时主线程继续处理其他逻辑
  3. 当socket上的数据已被读入用户缓冲区后,内核向应用程序发送一个信号,通知其数据已可用
  4. 通过应用程序注册的信号处理事件来选择一个工作线程来完成客户请求的业务逻辑处理。
  5. 工作线程完成之后会调用aio_write函数向内核注册socket上的写就绪事件,并且告诉内核用户写缓冲区的位置,以及设定写操作完成时通知应用程序的信号
  6. 主线程继续处理其他逻辑
  7. 当socket上的数据已被写入socke后,内核向应用程序发送一个信号,通知其数据发送完成
  8. 通过应用程序注册的信号处理事件来选择一个工作线程来进行善后处理,例如是否关闭socket
    在这里插入图片描述
    由于读/写事件是通过aio_read/air_write向内核中进行注册的,所以这里的epoll仅仅用来监听是否有新的连接到来,而不用于监听读写。

同步I/O模型模拟Proactor模式

当然我们也可以使用同步I/O模型来模拟Proactor模式。
其原理是由主线程来完成数据的读写操作,完成后向工作线程通知事件的完成,那么从工作线程的角度来看,他们就直接获得了数据读写的结果,接下来工作线程就只需要对读写结果进行业务逻辑处理

这里以epoll为例子,使用同步I/O模型实现的Proactor模式的工作流程如下:

  1. 主线程往epoll内核事件表中注册socket上的读就绪事件
  2. 主线程调用epoll_wait开始对socket的读事件进行监控
  3. 如果socket读就绪,epoll_wait会通知主线程,主线程从socket中读取数据,读取完成后将数据封装为请求对象插入请求队列中
  4. 请求队列上某个休眠的工作线程被唤醒,此时它会获取请求对象并且处理用户请求,然后后往epoll内核事件表中注册该socket的写就绪事件
  5. 主线程继续调用epoll_wait对socket的写事件进行监控
  6. 如果socket写就绪,epoll_wait会通知主线程,主线程往socket中写入服务器处理客户请求的结果。
    在这里插入图片描述

两者的优缺点

Reactor

Reactor实现了一个被动的事件分离和分发模型,服务等待请求事件的到来,再通过不受间断的同步处理事件,从而做出反应;

优点

扫描二维码关注公众号,回复: 11975636 查看本文章
  • Reactor实现相对简单,对于耗时短的处理场景处理高效
  • 操作系统可以在多个事件源上等待,并且避免了多线程编程相关的性能开销和编程复杂性
  • 事件的串行化对应用是透明的,可以顺序的同步执行而不需要加锁
  • 将与应用无关的多路分解和分配机制和与应用相关的回调函数分离开来

缺点

  • Reactor处理耗时长的操作会造成事件分发的阻塞,影响到后续事件的处理

适用场景

  • 同时接收多个服务请求,并且依次同步的处理它们的事件驱动程序

Proactor

Proactor实现了一个主动的事件分离和分发模型;这种设计允许多个任务并发的执行,从而提高吞吐量;并可执行耗时长的任务(各个任务间互不影响)

优点

  • Proactor性能更高,能够处理耗时长的并发场景

缺点

  • Proactor实现逻辑复杂,依赖操作系统对异步的支持,目前实现了纯异步操作的操作系统少,实现优秀的如windows IOCP,但由于其windows系统用于服务器的局限性,目前应用范围较小;而Unix/Linux系统对纯异步的支持有限,应用事件驱动的主流还是通过select/epoll来实现

适用场景

  • 异步接收和同时处理多个服务请求的事件驱动程序;

猜你喜欢

转载自blog.csdn.net/qq_35423154/article/details/108928668