Reactor模型与Proactor模型

简介: Reactor模型与Proactor模型

(本文是站在Java角度讲述这两个模型,所以只谈线程)。 在介绍这两种模型之前先介绍一下在I/O场景下同步、异步、阻塞、非阻塞的概念。 我们都知道我们的程序是运行在操作系统上的,我们程序和服务器硬件之间隔着个操作系统,一般情况下我们的服务器都是linux系统,为了安全考虑linux系统又分了:用户态和内核态


I/O操作得经历两个过程: 1、读存储设备数据到内核缓存 2、从内核缓存读数据到用户空间


1操作比2操作慢的多,因为去磁盘寻址啊等操作比较慢。


然后我们平日里针对I/O场景下说的阻塞I/O、非阻塞I/O指的就是1操作是否阻塞,也就是会立即返回一个状态值,还是会等待存储设备数据读取到内核缓存后在返回所需的数据。


而平日里说的同步I/O、异步I/O指的是2操作是否会阻塞。


Reactor模型


它是同步非阻塞模型。也称为Dispatcher模型。想想如果每一个连接过来我们都得建一个线程来处理这个连接,那连接一多线程不得爆满,那可能有人说上线程池,对线程池肯定是要上的。但这只能解决线程数的问题,但还有一个问题就是资源利用率的问题,当连接没断开的时候,当这个连接暂时没请求的时候你的线程是不是得阻塞着等着请求呀,那线程等于还是被人占用了,别的连接有请求的时候也用不到这个线程,资源的浪费啊,性能低啊。


那如何解决这个问题呢?


当然是等连接有请求的时候线程再上去处理。那这个事情得找个“人”来做,咱们业务线程就处理业务,就是得有个“人”来管理所有的连接,他发现哪个连接有请求了就分配业务线程来处理。


这就叫Reactor模型。上面说的那个"人"我们称为reactor,中文翻译时反应堆的意思,也就是他就是那个监视的人,如果有情况来了他就有所反应,分发任务给业务线程处理。

可以有单Reactor单线程,单Reactor多线程,多Reactor多线程 ###单Reactor单线程


image.png

select会一直监听着事件,事件来了之后给dispatch分发,如果建立请求的事件则分配的acceptor,由acceptor创建一个handler来处理后续的业务,如果不是建立请求的事件则分配个之前对应的handler来处理后续业务


这个情况的优点就是简单。。。没有多线程共享资源争抢导致的问题。缺点就是就单线程,浪费了多CPU,并且同一时刻只有一个handler能处理,其他的得等着。


听起来好像没啥用啊这样,是的绝大部分场景不适合,但是redis就是这样用的。因为它处理业务够快。所以这种适合在业务处理极快的情况下使用。 ###单Reactor多线程


image.png

当业务处理不快就上多线程咯。

这个模式和上面的区别就在于具体业务实现不由handler处理的,handler只负责read数据,将数据给业务线程,然后业务线程处理完毕之后返回结果给handler,由handler send给客户端 。 这个模式的优点就是可以充分利用CPU,适合业务处理不快的情况。缺点就是多线程之间共享资源的争抢产生的问题,并且只有一个Reactor来监听并响应,当请求量太大时,一个Reactor可能会成为性能瓶颈。 ###多Reactor多线程 所以多Reactor多线程就来啦。


image.png

mainReactor主要用来接受连接,由连接来就给acceptor,acceptor将新的连接分配个某个subReactor,然后这个subReactor将其加入自己的监听列表,并创建一个handler来处理这个连接。之后就都由这个subReactor来select监听来响应这个连接的请求,然后dispatch给对应的handler来read,业务处理,send。mainReactor就不管啦。

所以这种方案就等于主Reactor分流了,只有新的连接由主Reactor接受,老的连接都分给了subReactor来响应。


Proactor模型


它是异步非阻塞模型。中文翻译为前摄器。。不知道啥玩意,可以称之为主动器。也就是我们不必等待I/O数据准备好也就是内核缓存已经读数据到用户空间。这一切都有内核来帮我们搞定,数据准备好了之后就通知Proactor,然后Proactor就调用相应的Handler进行业务处理。相对于Reactor省去了遍历事件通知队列selector 的代价。


image.png

由initiator创建handler和proactor并通过Asynchronous Operation Processor注册到内核,然后Asynchronous Operation Processor完成I/O会通知proactor,proactor再调用对应的handler处理业务。


所以理论上Proactor的效率比Reactor高,但是linux并没有真正的实现Proactor模型,而是epoll模拟出Proactor模型。


相关文章
|
存储 前端开发 安全
C++一分钟之-未来与承诺:std::future与std::promise
【6月更文挑战第27天】`std::future`和`std::promise`是C++异步编程的关键工具,用于处理未完成任务的结果。`future`代表异步任务的结果容器,可阻塞等待或检查结果是否就绪;`promise`用于设置`future`的值,允许多线程间通信。常见问题包括异常安全、多重获取、线程同步和未检查状态。解决办法涉及智能指针管理、明确获取时机、确保线程安全以及检查未来状态。示例展示了使用`std::async`和`future`执行异步任务并获取结果。
704 2
|
11月前
|
机器学习/深度学习 人工智能 运维
日志别只会“看”,现在是该让AI帮你“算”了!
日志别只会“看”,现在是该让AI帮你“算”了!
1003 9
|
存储 Kubernetes 数据安全/隐私保护
k8s--配置存储 ConfigMap、Secret
k8s--配置存储 ConfigMap、Secret
|
编译器 C++ 开发者
C++一分钟之-属性(attributes)与属性语法
【7月更文挑战第3天】C++的属性(attributes)自C++11起允许附加编译器指令,如`[[nodiscard]]`和`[[maybe_unused]]`,影响优化和警告。注意属性放置、兼容性和适度使用,以确保代码清晰和可移植。示例展示了如何使用属性来提示编译器处理返回值和未使用变量,以及利用编译器扩展进行自动清理。属性是提升代码质量的工具,但应谨慎使用。
544 13
|
NoSQL 算法 Redis
Redis集群哈希槽数据分片
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽. 集群的每个节点负责一部分hash槽。这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。
612 0
Redis集群哈希槽数据分片
|
调度 C++ 开发者
C++一分钟之-认识协程(coroutine)
【6月更文挑战第30天】C++20引入的协程提供了一种轻量级的控制流抽象,便于异步编程,减少了对回调和状态机的依赖。协程包括使用`co_await`、`co_return`、`co_yield`的函数,以及协程柄和awaiter来控制执行。它们适合异步IO、生成器和轻量级任务调度。常见问题包括与线程混淆、不当使用`co_await`和资源泄漏。例如,斐波那契生成器协程展示了如何生成序列。正确理解和使用协程能简化异步代码,但需注意生命周期管理。
793 4
|
API Windows
Reactor和Proactor网络模型的区别
Reactor和Proactor网络模型的区别
251 0
|
存储 算法 数据处理
C++一分钟之-范围基础:views与ranges
【7月更文挑战第1天】C++20的Ranges库简化了集合操作,引入了Range(具有begin()和end()的对象)和View(延迟计算的Range)。常见问题包括混淆Range与Container、忽视View的延迟性和错误修改只读View。要避免错误,需理解Range概念、明确操作执行时机并检查View的可变性。代码示例展示了如何过滤并平方vector中的奇数,体现Range的使用。范围库带来了代码的简洁和效率,但理解其工作原理至关重要。
488 0
|
数据安全/隐私保护 云计算
视频会议
视频会议
713 2
|
算法 程序员 开发工具
代码随想录 学习记录(1)
代码随想录 学习记录(1)
797 0

热门文章

最新文章