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 { // 处理完成事件的具体逻辑 } };