Proactor 与 Reactor

Reactor模式用于同步I/O,Proactor运用于异步I/O操作 阻塞模型 同步和异步 针对应用程序和内核交互而言 同步:用户进程触发I/O操作,等待或轮询去查看I/O操作是否就绪 异步:用户进程触发I/O操作后,去做自己的事情,I/O操作完成后给予通知 阻塞和非阻塞 进程在访问数据的时候,根据I/O操作的就绪状态采取不同的方式,即读取或写入操作函数的实现方式 阻塞:读取或写入函数将一直等待 非阻塞:读取或写入函数回立即返回一个状态值 常见I/O模型 以小明下载王者农药和打开游戏两个任务为例 同步阻塞 点击下载—盯着下载条—到100%下载完成—打开游戏 同步:等待下载完成的结果通知 阻塞:盯着下载条,没有处理其余任务 用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行 同布非阻塞 点击下载—刷抖音/看B站—时不时返回查看下载进度—下载完成:点击打开游戏 同步:等待下载完成的结果通知 非阻塞:下载过程可以去处理其余任务 用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费 异步阻塞 小明开启了下载完成的震动通知 点击下载—单纯等待,不主动查看—收到震动通知—打开游戏 异步:下载结果以震动的方式告知 阻塞:等待这个震动,没有去做别的 发起I/O后足赛等待,根据到达的通知来进行数据处理 异步非阻塞 小明开启了下载完成的震动通知 点击下载—刷抖音/看B站—收到震动通知—打开游戏 发起I/O后立即返回,等I/O完成后回得到完成通知,用户进程根据通知来进行数据处理 归纳 同步/异步关注的是消息通知的机制 阻塞/非阻塞关注的是程序(线程)等待消息通知时的状态。 Reactor和Proactor 阻塞与非阻塞都可以理解为同步范畴下才有的概念,对于异步,就不会再去分阻塞非阻塞。 Reactor 要求主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生 有的话就立即将事件通知工作线程(逻辑单元)数据的读写,接受新的连接以及处理客户请求均在工作线程中完成; 除此之外,逻辑线程不作任何工作。 中心思想: 将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程/进程阻塞在多路复用器上; 一旦有I/O事件到来或是准备就绪(文件描述符或socket可读、写),多路复用器返回并将事先注册的相应I/O事件分发到对应的处理器中。 Reactor是一种事件驱动机制,和普通函数调用的不同之处在于: 应用程序不是主动的调用某个API完成处理,而是恰恰相反 Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的事件发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。用“好莱坞原则”来形容Reactor再合适不过了:不要打电话给我们,我们会打电话通知你。 应用场景 场景: 长途客车在路途上,有人上车有人下车,但是乘客总是希望能够在客车上得到休息。 传统做法: 每隔一段时间(或每一个站),司机或售票员对每一个乘客询问是否下车。 Reactor做法:汽车是乘客访问的主体(Reactor),乘客上车后,到售票员(acceptor)处登记,之后乘客便可以休息睡觉去了,当到达乘客所要到达的目的地时(指定的事件发生,乘客到了下车地点),售票员将其唤醒即可。 组成 Reactor模式是基于事件驱动的分发处理模型 有一个或多个并发输入源,有一个Service Handler,有多个Request Handlers 这个Service Handler会同步的将输入的请求(Event)多路复用的分发给相应的Request Handler。 Proactor Proactor将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。 事件句柄初始化一个异步读操作,此时该句柄并不在意异步操作结果,而是要获得完成事件而注册 事件多路器等待直到io事件完成 当事件多路器等待io事件时,操作系统在一个并行的内核线程上处理读操作,并将数据放到一个用户定义的缓冲中,并通知事件多路器操作完成。 事件多路器调用事件句柄 事件句柄从用户定义缓冲中获得用户数据并操作,然后开始新的异步操作并将控释返回事件多路器 在Reactor模式中,事件分离者等待某个事件或者可应用或个操作的状态发生(比如文件描述符可读写,或者是socket可读写),事件分离器就把这个事件传给事先注册的处理器(事件处理函数或者回调函数),由后者来做实际的读写操作。 ...

2019/12/08 · Aris