事件处理模式
Reactor
-
Reactor是非阻塞同步网络模式
-
Reactor的组成
-
Handle(句柄或描述符):本质上表示一种资源,是由操作系统提供的;该资源用于表示一个个的事件,事件既可以来自于外部,也可以来自于内部;外部事件比如说客户端的连接请求,客户端发送过来的数据等;内部事件比如说操作系统产生的定时事件等。它本质上就是一个文件描述符,Handle是事件产生的发源地
-
Synchronous Event Demultiplexer(同步事件分离器):它本身是一个系统调用,用于等待事件的发生(事件可能是一个,也可能是多个)。调用方在调用它的时候会被阻塞,一直阻塞到同步事件分离器上有事件产生为止。对于Linux来说,同步事件分离器指的就是常用的I/O多路复用机制,比如说select、poll、epoll等
-
Event Handler(事件处理器):本身由多个回调方法构成,这些回调方法构成了与应用相关的对于某个事件的反馈机制
-
Concrete Event Handler(具体事件处理器):是事件处理器的实现。它本身实现了事件处理器所提供的各种回调方法,从而实现了特定于业务的逻辑。它本质上就是我们所编写的一个个的处理器实现
-
Initiation Dispatcher(初始分发器):实际上就是Reactor角色。它本身定义了一些规范,这些规范用于控制事件的调度方式,同时又提供了应用进行事件处理器的注册、删除等设施。它本身是整个事件处理器的核心所在,Initiation Dispatcher会通过Synchronous Event Demultiplexer来等待事件的发生。一旦事件发生,Initiation Dispatcher首先会分离出每一个事件,然后调用事件处理器,最后调用相关的回调方法来处理这些事件
-
-
Reactor处理流程
- 初始化Initiation Dispatcher,然后将若干个Concrete Event Handler注册到Initiation Dispatcher中。当应用向Initiation Dispatcher注册Concrete Event Handler时,会在注册的同时指定感兴趣的事件,即,应用会标识出该事件处理器希望Initiation Dispatcher在某些事件发生时向其发出通知,事件通过Handle来标识,而Concrete Event Handler又持有该Handle。这样,事件 -> Handle -> Concrete Event Handler 就关联起来了
- Initiation Dispatcher 会要求每个事件处理器向其传递内部的Handle。该Handle向操作系统标识了事件处理器
- 当所有的Concrete Event Handler都注册完毕后,应用会调用handle_events方法来启动Initiation Dispatcher的事件循环。这是,Initiation Dispatcher会将每个注册的Concrete Event Handler的Handle合并起来,并使用Synchronous Event Demultiplexer(同步事件分离器)同步阻塞的等待事件的发生
- 当与某个事件源对应的Handle变为ready状态时(比如说,TCP socket变为等待读状态时),Synchronous Event Demultiplexer就会通知Initiation Dispatcher
- Initiation Dispatcher会触发事件处理器的回调方法,从而响应这个处于ready状态的Handle。当事件发生时,Initiation Dispatcher会将被事件源激活的Handle作为
key
来寻找并分发恰当的事件处理器回调方法 - Initiation Dispatcher会回调事件处理器的handle_event(type)回调方法来执行特定于应用的功能(开发者自己所编写的功能),从而相应这个事件。所发生的事件类型可以作为该方法参数并被该方法内部使用来执行额外的特定于服务的分离与分发
Proactor
- Proactor 是异步⽹络模式
- 异步 I/O是
内核数据准备好
和数据从内核态拷贝到用户态
两个过程都不⽤等待 - 当我们发起aio_read (异步I/O) 之后,就立即返回,内核自动将数据从内核空间拷贝到内核空间,这个拷贝过程同样是异步的,内核自动完成,与同步操作不一样,应⽤程序并不需要主动发起拷贝动作 动作
- 异步 I/O比同步 I/O性能好,因为异步 I/O在
内核数据准备好
和数据从内核态拷贝到用户态
两个过程都不⽤等待
Reactor和Proactor区别
-
Reactor 是非阻塞同步网络模式,感知的是就绪可读写事件。在每次感知到有事件发生(比如可读就绪事件)后,就需要应用进程主动调用read方法来完成数据的读取,也就是要应用进程主动将socket接收缓冲区重得数据读到应用进程内存中,这个过程是同步的,读取完数据后应用进程才能处理数据
-
Proactor 是异步网络模式, 感知的是已完成的读写事件。再发起异步读写请求时,需要传入数据缓冲区的地址(用来存放结果数据)等信息,这样系统内核才可以自动帮我们把数据的读写工作完成,这里的读写工作全程由操作系统内核来做,并不需要像Reactor那样还需要应用进程主动发起read/write同步操作来读写数据,操作系统完成读写工作后,就会通知应用进程直接处理数据