文章目录
-
- 1、传统IO模型
- 2、reactor模型
-
- 2.1、单reactor单线程
- 2.2、单reactor多线程
- 2.3、主从reactor多线程
- 总结
1、传统IO模型
传统IOjava代码传送门。
传统IO,称阻塞IO(BIO)。当客户端与服务端进行连接时,每一个客户端都会对应服务端一个单独的线程与其连接,这个thread完成对应的业务处理。当没有业务处理时,这个线程也会一直存在,一直等待客户端发送信息。
当客户端没有信息传输的时候,服务端会一直卡在
inputStream.read
。
因此,传统IO,弊端很明显,当大量客户端连接服务器,但是信息发送不频繁时,会造成大量线程的浪费。
2、reactor模型
当客户端没有信息传输时,无需所有的线程都在等待状态。因此reactor引入selector的概念,selector实质上是完成了一个转发的功能,所有的客户端与selector连接,如果有客户端发送信息时,转发给一个线程进行处理。因此reactor模型也称为分发者模式。
reactor是一个事件驱动模型,当selector收到对应事件后,可以按照对应的事件通知不同的handler进行处理。有连接事件,读事件,写事件等。
当客户端没有事件产生时,客户端只与selector连接。避免的线程的浪费。
2.1、单reactor单线程
代码传送门。
此思路比较简单,没有多线程之间的通讯,功能全在一个线程中执行。弊端也很明显,单个线程无法发挥发挥CPU的性能。在业务处理中,系统的性能很容易达到瓶颈。
因此,此客户端适应于客户端数量有限,而且handler处理速度非常快的场景。例如redis的在业务处理的世界复杂度O(1)的情况。
2.2、单reactor多线程
reactor对象通过selector监控客户端的请求事件,收到事件之后进行分发。根据不同的事件进行分发。accept复杂连接事件,send负责发送事件,read负责读事件,handler复杂业务处理。这个模型可以充分发挥多喝CPU的处理能力。但是selector在单线程中运行,也容易出现性能瓶颈。
2.3、主从reactor多线程
- Reactor主线程 MainReactor 对象通过select 监听连接事件, 收到事件后,通过Acceptor 处理连接事件
- 当 Acceptor 处理连接事件后,MainReactor 将连接分配给SubReactor
- subreactor 将连接加入到连接队列进行监听,并创建handler进行各种事件处理
- 当有新事件发生时, subreactor 就会调用对应的handler处理
- handler 通过read 读取数据,分发给后面的worker 线程处理
- worker 线程池分配独立的worker 线程进行业务处理,并返回结果
- handler 收到响应的结果后,再通过send 将结果返回给client
- Reactor 主线程可以对应多个Reactor 子线程, 即MainRecator 可以关联多个SubReactor
优缺点说明:
- 优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。
- 优点:父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。
- 缺点:编程复杂度较高
总结
如此看来reactor模型可以这样比喻:
单 Reactor 单线程,前台接待员和服务员是同一个人,全程为顾客服。
单 Reactor 多线程,1 个前台接待员,多个服务员,接待员只负责接待。
主从 Reactor 多线程,多个前台接待员,多个服务生。
reactor模型响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销扩展性好,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源复用性好,Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性。