网络IO管理 (二)--服务器线程模型Reactor和Proactor

一、概述

对高并发编程, 网络连接上的消息处理,可以分为两个阶段:等待消息准备好、消息处理。
高并发编程方法当然就是把两个阶段分开处理。即,等待消息准备好的代码段,与处理消息的代码段是分离的。
多路复用就是处理等待消息准备好这件事的,但它可以同时处理多个连接!
作为一个高性能服务器程序通常需要考虑处理三类事件: I/O 事件,定时事件及信号。
两种高效的事件处理模型: Reactor 和 Proactor


二、Reactor

2.1 Reactor机制

普通函数的调用机制:
程序调用某函数–>函数执行–>程序等待–>函数将结果和控制权返回给程序–>程序继续处理…

Reactor模式基本思想:
在这里插入图片描述
两个关键组成:
1)Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。
2)Handlers:处理程序执行 I/O 事件要完成的实际事件。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。

与普通函数调用机制不同,reactor释义“反应堆”,是一种事件驱动机制,应用程序不是主动的调用某个API完成处理,而是逆置了事件处理流程,应用程序需要提供相应的接口并注册到reactor上。如果相应的事件发生,reactor将主动调用程序注册的接口(回调函数)。
在这里插入图片描述

Reactor 模式是处理并发 I/O 比较常见的一种模式,用于同步 I/O,中心思想是将所有要处理的 I/O 事件注册到一个中心 I/O 多路复用器上,同时主线程/进程阻塞在多路复用器上;一旦有 I/O 事件到来或是准备就绪(文件描述符或 socket 可读、写),多路复用器返回并将事先注册的相应 I/O 事件分发到对应的处理器中。


2.2 Reactor模型

Reactor模型三个重要组件

  • 多路复用器:由操作系统提供,在linux上一般时select、poll、epoll等系统调用等。
  • 事件分发器:将多路复用器中返回的就绪事件分到对应的处理函数中。
  • 事件处理器:负责处理特定事件的处理函数。
    在这里插入图片描述

具体流程

  1. 注册读就绪事件和相应的事件处理器。
  2. 事件分离器等待事件。
  3. 事件到来,激活分离器,分离器调用事件对应的处理器。
  4. 事件处理器完成实际的读操作,处理读取到的数据,注册新的事件,然后返还控制权。



Reactor模式是编写高性能网络服务器的必备技术之一,优点有

  • 响应快,不必为单个同步的时间所阻塞,虽然Reactor本身依然是同步的。
  • 编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销。
  • 可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源。
  • 可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性。

Reactor 模型开发效率上比起直接使用 IO 复用要高,它通常是单线程的,设计目标是希望单线程使用一颗 CPU 的全部资源,但也有附带优点,即每个事件处理中很多时候可以不考虑共享资源的互斥访问

可是缺点也是明显的,现在的硬件发展,已经不再遵循摩尔定律, CPU 的频率受制于材料的限制不再有大的提升,而改为是从核数的增加上提升能力,当程序需要使用多核资源时, Reactor 模型就会悲剧, 为什么呢?
如果程序业务很简单,例如只是简单的访问一些提供了并发访问的服务,就可以直接开启多个反应堆,每个反应堆对应一颗CPU核心,这些反应堆上跑的请求互不相关,这是完全可以利用多核的,比如nginx这样的http静态服务器。


三、Proactor

3.1 Proactor机制

在这里插入图片描述


3.2 Proactor模型

在这里插入图片描述
具体流程

  1. 处理器发起异步操作,并关注IO完成事件。
  2. 事件分离器等待操作完成事件。
  3. 分离器等待过程中,内核并行执行实际的IO操作,并将结果数据存入用户自定义缓冲区,最后通知事件分离器读操作完成。
  4. IO完成后,通过事件分离器呼唤处理器。
  5. 事件处理器处理用户自定义缓冲区的数据。



Proactor特点
Proactor最大特点是使用异步IO。所有的IO操作都交由系统提供的异步IO执行接口执行
工作线程仅仅负责业务逻辑。在Proactor中,用户函数启动一个异步的文件操作,同时将这个操作注册到多路复用器上。
多路复用器并不关心文件是否可读或可写,而是关心这个异步操作是否完成。异步操作是操作系统完成,用户不需要关心。
多路复用器等待直到有完成通知到来。当操作系统完成了读文件操作——将读到的数据复制到了用户先前提供的缓冲区之后,通知多路复用器相关操作已完成。多路复用器再调用相应的处理程序,处理数据。

Proactor 增加了编程的复杂度,但给工作线程带来了更高的效率。 Proactor 可以在系统态将读写优化,利用 I/O 并行能力,提供一个高性能单线程模型。

windows系统,提供IOCP支持高并发,较常采用 Proactor 的模型利用完成端口来实现服务器。
linux系统,采用epoll机制实现,以 Reactor 模型为主。

猜你喜欢

转载自blog.csdn.net/locahuang/article/details/111478998