I/O 模式 + Reactor/Proactor笔记

1.同步、非同步 、阻塞、非阻塞 I/O 模式的操作理解

同步、异步:主要针对的对象是进程与内核之间的交互过程。同步在进程触发I/O操作的时候,会主动以等待或者轮询的方式去查看内核中的I/O操作是否就绪。异步就是进程触发I/O操作之后就不管这个操作了,可以去干其他的事,反而内核完成这个I/O操作之后,内核会给异步进程一个I/O完成的通知。异步主要特点就是会得到一个通知。
阻塞、非阻塞:主要针对的对象是进程访问数据的过程。当I/O操作就绪之后,阻塞方式下的读取或者写入函数会抑制等待数据缓冲区中的数据状态(有数据或者无数据)的改变而随之改变。非阻塞式的读取或者写入操作不管数据缓冲区里面是什么样的状态都会返回数据或者一个状态值。
通常I/O操作抽象为两个状态:
1.用户态等待内核态将数据准备好,即同步、异步申请 I/O。
2.将数据将内核态拷贝到用户态,即阻塞、非阻塞读取数据。

同步阻塞:在以上两个阶段,用户态都会阻塞等待内核准备数据以及拷贝数据。
在这里插入图片描述
同步非阻塞:在第一阶段内核准备数据的过程中,用户态不会阻塞,会以轮询的方式返回状态值,儿第二个阶段拷贝数据阶段,一样会阻塞等待数据拷贝完成。
在这里插入图片描述
I/O多路复用:I/O复用也是属于同步的。它和同步阻塞模式有一些一样,两个阶段都是阻塞的,但是I/O复用利用较小的代价来实现了同时监听多个I/O事件的目的。利用一个线程来同时监听多个文件描述符,然后将就绪的文件描述符关联的事件交给后面的内核来处理(这里用多种操作方式,线程池等)。I/O复用的实现如今还多是依赖于操作系统的select、poll、epoll等框架。目前java,linux主流还是用epoll同步非阻塞式I/O来是想大量并发的服务。epoll的机制请参考
epoll实现原理在这里插入图片描述
异步I/O:第一阶段和内核态交互表达I/O请求后立马返回,直到最后数据拷贝完成,内核会返回一个信号到用户态。这也是最重要的一点。
在这里插入图片描述

2. 介绍下proactor和reactor

reactor、proactor两种高效的事件处理模式
Reactor:(同步I/O模型),中心思想是将所要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程开始阻塞(工作线程也在阻塞)监听文件描述符判断是否有事件发生,将有事件发生的文件描述符按照事件的类型分发到相应的工作处理线程中,等待工作线程的处理,而主线程则继续监听。其中读写、接受新的客户端连接、新的客户的请求都有相应的工作线程来完成。

Reactor是一种事件驱动机制,和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的事件发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。用“好莱坞原则”来形容Reactor再合适不过了:不要打电话给我们,我们会打电话通知你。

Proactor:(异步I/O模型),与Reactor思想不同,Proactor的所有I/O操作都由主线程和内核来处理,其他的工作线程仅仅负责逻辑业务。在Proactor模式中,事件处理者(或者代由事件分离者发起)直接发起一个异步读写操作(相当于请求),而实际的工作是由操作系统来完成的。发起时,需要提供的参数包括用于存放读到数据的缓存区,读的数据大小,或者用于存放外发数据的缓存区,以及这个请求完后的回调函数等信息。事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者回调。

可以看出两者的区别:
Reactor是在事件发生时就通知事先注册的事件(读写由处理函数完成);
Proactor是在事件发生时进行异步I/O(读写由OS完成),待IO完成事件分离器才调度处理器来处理。

3.reactor的组成

1.Reactor:反应堆管理器(主线程)整个反应堆核心,
1.用于注册、删除事件的文件描述符,
2.运行事件循环
3.监听事件的文件描述符是否就绪,将就绪的事件分发到回调函数或者分发到同步事件多路分离器。
2.同步事件多路分离器(event demultiplexer):事件的到来是随机的、异步的,无法预知程序何时收到一个客户连接请求或收到一个信号。所以程序要循环等待并处理事件,这就是事件循环。在事件循环中,等待事件一般使用I/O复用技术实现。在linux系统上一般是select、poll、epol_waitl等系统调用,用来等待一个或多个事件的发生。I/O框架库一般将各种I/O复用系统调用封装成统一的接口,称为事件多路分离器。调用者会被阻塞,直到分离器分离的描述符集上有事件发生。
3.事件处理器(event handler):I/O框架库提供的事件处理器通常是由一个或多个模板函数组成的接口。这些模板函数描述了和应用程序相关的对某个事件的操作,用户需要继承它来实现自己的事件处理器,即具体事件处理器。因此,事件处理器中的回调函数一般声明为虚函数,以支持用户拓展。
4. 具体的事件处理器(concrete event handler):是事件处理器接口的实现。它实现了应用程序提供的某个服务。每个具体的事件处理器总和一个描述符相关。它使用描述符来识别事件、识别应用程序提供的服务。

猜你喜欢

转载自blog.csdn.net/GJQJFJ/article/details/106606118