深入浅出Reactor和Proactor模式

简介: 深入浅出Reactor和Proactor模式

       Reactor模式和Proactor模式是两种常见的设计模式,用于处理事件驱动的并发编程。它们在处理IO操作时有着不同的工作方式和特点。


对于到来的IO事件(或是其他的信号/定时事件),又有两种事件处理模式:


  • Reactor模式:要求主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生(可读、可写),若有,则立即通知工作线程,将socket可读可写事件放入请求队列,读写数据、接受新连接及处理客户请求均在工作线程中完成。(需要区别读和写事件)
  • Proactor模式:主线程和内核负责处理读写数据、接受新连接等I/O操作,工作线程仅负责业务逻辑(给予相应的返回url),如处理客户请求。

Reactor模式:

工作方式:Reactor模式使用一个事件循环/事件轮询器(通常是主线程),负责监听和分发IO事件。当有IO事件发生时,Reactor会调用相应的处理函数进行处理。

优点:

  • 简单且易于理解和实现。通常只需要一个事件循环器以及事件处理函数即可实现。
  • 可以处理大量的并发连接,因为使用一个线程来处理所有的IO事件,减少了线程切换的开销

缺点:

  • 对于处理耗时的IO操作阻塞,会导致整个Reactor的处理能力下降,无法充分利用CPU资源。
  • 无法利用多核处理器的优势,因为只有一个线程用于处理IO事件。

具体框架:

class Reactor {
public:
    // 构造函数,初始化事件循环
    Reactor();
 
    // 注册事件处理器
    void registerEventHandler(EventHandler* handler, EventType type);
 
    // 事件循环
    void eventLoop();
 
private:
    // 事件处理器映射表
    std::map<EventType, EventHandler*> eventHandlers;
};
 
// 事件处理器接口
class EventHandler {
public:
    virtual void handleEvent() = 0;
};
 
// 具体的事件处理器
class ConcreteEventHandler : public EventHandler {
public:
    virtual void handleEvent() override {
        // 处理事件的具体逻辑
    }
};

Proactor模式:

工作方式:Proactor模式使用多线程来处理IO事件。一个线程负责发起IO操作,当操作完成后,另一个线程会收到通知并处理完成的IO操作。

(图借鉴网络)

优点:

  • 可以充分利用多核处理器的优势来处理并发IO操作。
  • 每个线程可以同时处理多个IO事件。
  • 高效利用CPU资源,即使有部分IO操作阻塞也不会影响其他线程的正常工作。

缺点:

  • 实现较复杂,涉及多线程之间的同步和通信,需要额外的开销。
  • 每个IO操作都需要启动两个线程,可能会导致系统开销较大。

具体框架:

class Proactor {
public:
    // 构造函数,初始化异步操作队列
    Proactor();
 
    // 异步读操作
    void asyncRead(File* file, CompletionHandler* handler);
 
    // 异步写操作
    void asyncWrite(File* file, const std::string& data, CompletionHandler* handler);
 
    // 事件循环
    void eventLoop();
 
private:
    // 异步操作队列
    std::queue<AsyncOperation*> asyncOperations;
};
 
// 异步操作接口
class AsyncOperation {
public:
    virtual void execute() = 0;
};
 
// 异步读操作具体实现
class AsyncReadOperation : public AsyncOperation {
public:
    virtual void execute() override {
        // 执行异步读操作
    }
};
 
// 异步写操作具体实现
class AsyncWriteOperation : public AsyncOperation {
public:
    virtual void execute() override {
        // 执行异步写操作
    }
};
 
// 完成处理器接口
class CompletionHandler {
public:
    virtual void handleCompletion() = 0;
};
 
// 具体的完成处理器
class ConcreteCompletionHandler : public CompletionHandler {
public:
    virtual void handleCompletion() override {
        // 处理完成事件的具体逻辑
    }
};
相关文章
|
7月前
|
消息中间件 Kubernetes NoSQL
Reactor 和 Proactor 区别
Reactor 和 Proactor 区别
|
2月前
|
Java
Reactor模式
通过一个具体的Java代码示例展示了如何在NIO框架下实现Reactor模式,用于处理网络IO事件,包括事件的接收、分发和处理。
41 4
Reactor模式
|
2月前
|
NoSQL Java Redis
Reactor实战,创建一个简单的单线程Reactor(理解了就相当于理解了多线程的Reactor)
本文通过一个简单的单线程Reactor模式的Java代码示例,展示了如何使用NIO创建一个服务端,处理客户端的连接和数据读写,帮助理解Reactor模式的核心原理。
43 0
Reactor实战,创建一个简单的单线程Reactor(理解了就相当于理解了多线程的Reactor)
|
7月前
|
监控 安全 Linux
reactor的原理与实现
前情回顾 网络IO,会涉及到两个系统对象:   一个是用户空间调用的进程或线程   一个是内核空间的内核系统 如果发生IO操作read时,会奖励两个阶段:
80 1
|
7月前
|
缓存
2.1.2事件驱动reactor的原理与实现
2.1.2事件驱动reactor的原理与实现
|
7月前
|
API Windows
Reactor和Proactor网络模型的区别
Reactor和Proactor网络模型的区别
|
7月前
|
监控 Java 应用服务中间件
Reactor反应器模式
在Java的OIO编程中,最初和最原始的网络服务器程序使用一个while循环,不断地监听端口是否有新的连接,如果有就调用一个处理函数来处理。这种方法最大的问题就是如果前一个网络连接的处理没有结束,那么后面的连接请求没法被接收,于是后面的请求统统会被阻塞住,服务器的吞吐量就太低了。 为了解决这个严重的连接阻塞问题,出现了一个即为经典模式:Connection Per Thread。即对于每一个新的网络连接都分配一个线程,每个线程都独自处理自己负责的输入和输出,任何socket连接的输入和输出处理不会阻塞到后面新socket连接的监听和建立。早期版本的Tomcat服务器就是这样实现的。
|
网络协议 数据处理
Reactor模式(二)
Reactor模式
88 0
|
设计模式 网络协议 数据处理
Reactor模式(一)
Reactor模式
130 0
|
网络协议 Java Linux
Reactor模式笔记
Reactor模式笔记
150 0
Reactor模式笔记