什么是Reactor模型

Reactor 模型 也可以叫Reactor 模式也可以,毕竟设计模式(design pattern)。Reactor模型(Reactor Pattern)比较生硬的翻译就是反应器模式。它是一种事件处理模式(event handing pattern),用于处理一个或多个并发输入的服务请求给服务处理器(service handler)。服务处理器(service handler)将请求多路分解同步派发给业务关联的请求处理器(request handler)。

Reactor 模式的组成

资源(resource):任何向系统输入的请求,或者消耗系统输出。(client request)

同步事件多路分解器(Synchronous Event Demultiplexer):使用一个事件循环去阻塞所有的资源,当同步资源没有被阻塞多路分解器会把资源发送给dispatcher(分配器)。

工作逻辑:如果一个资源没有被读取完就会被阻塞,多路分解器就会使用select()方法在这个资源上,直到这个资源可以被读取,在同步调用read()方法使资源不被阻塞,同时多路分解器吧资源分配给分配器(dispatcher)

分配器(dispatcher):处理注册和和非注册(注销)的请求处理器,分配资源从多路分解器上获取的资源(请求)给关联的请求处理器(request handler (处理器) )

请求处理器(request handler (处理器) ):一个应用定义和资源相关的请求处理器。

下面图能更直观展示Reactor模式和EventLoop的关系

Reactor模式类型

Reactor模式的几种类型:单Reactor单线程模式,单Reactor多线程模式,多Reactor多线程模式。

单 Reactor (反应器) 单线程模式

Reactor模式都运行在单个线程里面,当请求增大时单个线程无法承受压力而性能不足。一般使用比较少

单 Reactor (反应器) 多线程模式

多线程模式,把多路分解器,分配器用单独线程去做,请求处理器的业务处理交给线程池处理。提高了资源处理能力,而且把业务与非业务部分抽离。

这种模式的不足是多路分解器,分配器承担了主要压力,与单线程相比性能有所提高,但是在高并发场景仍然会出现资源不够的问题(单线程无法处理大量请求链接的建立)

多 Reactor (反应器) 多线程模式

多Reactor多模型模式:多Reactor模式把Reactor分成两个Reactor,主Reactor和从Reactor。主Reactor主要处理链接建立,从Reaator负责分发和IO读写。主Reactor(多路分解器+分配器)分配器主要就是把事件请求分给建立链接还是给从Reactor。从Reactor(多路分解器+分配器)这里分配器主要就是把资源分配给请求处理器。这里主Reactor是只有一个,但是从Reactor可以有多个,而不是只有一个。

EventLoop(事件循环)

什么是Event Loop

Event Loop是一个程序结构或者设计模式,它在程序中是用来等待,调度事件或者消息。Event Loop处理内部或者外部的请求(通常这些请求都会一直等待,直到有返回给他们),当请求符合Event Loop所监听的事件,就会分配给对应的事件处理器。

事件循环常常用于Reactor模式的连接器(用于连接请求与处理器,也就是Reactor模式中的Synchronous Event Demultiplexer)。如果事件提供对于状态接口,事件循环可以seleted(符合条件)事件把这个事件Polled(抛出去)selected-polled模式。

EventLoop的应用有很多,比较经典的就是Node上使用,因为JavaScript是单线程,但是单线程为了提高效率使用Event Loop来提高Node的使用效率。

因为JavaScript是单线程的。就意味着所有任务都需要排队,前一个任务结束,后一个任务才能执行。前一个任务耗时很长,后一个任务也得一直等着。但是IO设备(比如ajax网络请求)很慢,CPU一直初一显得状态,这样就很不合理了。

所以,其实主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。于是有了同步任务异步任务

1、写的JavaScript脚本会交给V8引擎解析。
2、解析后的代码,调用 Node 的API,Node会交给Libuv库处理。向EventLoop中添加事件。
3、Libuv库将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。
4、V8引擎再将结果返回给用户。

主线程上的异步操作,并不会阻塞,而是挂起(sleep/wait)。当处理完异步会把已经处理好的数据放进事件队列,当主线程执行完从上执行完EventQueue事件后重新在获取,异步操作是否执行完成,如此往复循环。

主线程就是执行查找和循环的线程,不会阻塞,只会不停获取可执行的事件,然后执行(分发给各个执行工作线程)。单Reactor多线程,欧式。

外部输入数据–>轮询阶段(poll)–>检查阶段(check)–>关闭事件回调阶段(close callback)–>定时器检测阶段(timer)–>I/O事件回调阶段(I/O callbacks)–>闲置阶段(idle, prepare)–>轮询阶段。

杂记

demultiplexer与multiplexer

multiplexer和demultiplexer来自通信领域,多路复用能够将多个低速信道整合到一个高速信道进行传输,进而有效地利用了高速信道。

多路复用根据使用的技术可以分为时分复用(TDM)、频分复用(FDM)、空分复用(SDM)和码分复用(CDM)。

multiplexer:是一种多路复用器,各个低速信道的信号通过多路复用器(MUX,多工器)组合成一路可以在高速信道传输的信号。

demultiplexer:分路器(DEMUX,多路分解器)将高速信道传输的信号转换成多个低速信道的信号,并且转发给对应的低速信道。

JavaScript为什么单线程

JavaScript语言最大特点就是单线程,但是这里的单线程指的是主线程是单线程的。那为什么js要单线程呢? 因为,JS主要用于操作DOM,如果是有两个线程,一个在DOM上添加内容,一个在DOM上删除内容,此时浏览器该以哪个为准呢? 所以为了避免复杂性,JavaScript从诞生起就是单线程的。