← 返回题目列表

Proactor 和 Reactor 有什么区别?

高频 中等 第 12 / 27 题 更新于 2026/07/28
ReactorProactor事件驱动异步IO网络编程

简化版

两者都是高并发的事件驱动模型,区别在于基于「就绪」还是「完成」Reactor 基于同步 IO:事件「就绪」时通知你(「有数据可读了」),然后你自己去读写(数据拷贝由应用做)。Proactor 基于异步 IO:你发起异步读写后不管,内核把 IO 全部做完(包括数据拷贝),「完成」时才通知你(「数据已经在你缓冲区里了」)。简记:Reactor 说「能读了,你来读」,Proactor 说「读完了,给你」。

详细版

维度ReactorProactor
基于IO 就绪IO 完成
底层 IO同步 IO(多路复用 epoll)异步 IO(AIO / IOCP)
谁做数据拷贝应用(就绪后自己 read/write)内核(应用不参与)
通知含义「fd 可读/可写了」「读/写已完成,数据就绪」
典型实现Linux epoll、Netty、RedisWindows IOCP
  • Reactor:用 epoll 监听事件,当某个 fd「可读」时通知应用,应用再调用 read 把数据从内核拷到用户空间——数据拷贝这步是应用同步做的。所以 Reactor 建立在**同步非阻塞 IO(多路复用)**之上。
  • Proactor:应用发起一个异步读(告诉内核「读到这个缓冲区」)后就去干别的,内核完成「等待 + 数据拷贝」全过程,完成后通知应用「数据已在缓冲区」。应用完全不参与 IO 操作,只处理已就绪的数据。所以 Proactor 建立在真正的异步 IO之上。

完整版教学

一、核心区别:就绪 vs 完成

Reactor 和 Proactor 的分水岭,就是那个 IO 事件到底代表「就绪」还是「完成」:

  • Reactor 基于「就绪(readiness)」:它告诉你「现在可以读了」(数据到内核缓冲区了),但读这个动作还得你自己做——你收到通知后调 read,把数据从内核拷到用户空间。数据拷贝是应用同步完成的。
  • Proactor 基于「完成(completion)」:它告诉你「已经读完了」——你之前发起的异步读,内核已经把数据拷到你指定的缓冲区了,你直接用即可。整个读操作(等待 + 拷贝)都是内核做的,应用没参与。

这样对照:Reactor 是「事件通知」(能读了你来读),Proactor 是「完成通知」(读完了给你)。 这个区别决定了两者一个基于同步 IO、一个基于异步 IO。

二、和 IO 模型的对应关系

这两个模式其实是「IO 模型」在架构层面的体现(详见「五种 IO 模型」那道题):

  • Reactor ← IO 多路复用(同步 IO):epoll 负责「等待就绪」(阶段①),就绪后应用自己 read 做「数据拷贝」(阶段②)——阶段②是同步的,所以 Reactor 是同步模型;
  • Proactor ← 异步 IO(AIO):内核把「等待 + 拷贝」两个阶段全包了,完成后通知——所以 Proactor 是异步模型。

所以记忆很简单:Reactor 对应同步 IO(多路复用),Proactor 对应异步 IO。 前者应用要「亲自读写」,后者「内核读写完给你」。

三、为什么 Linux 上主流是 Reactor

理论上 Proactor(异步)编程更省心——应用不用管 IO 细节。但现实中 Linux 高性能网络库几乎都用 Reactor(Netty、Redis),原因是:

  • Linux 的原生异步 IO(AIO)长期不成熟:对网络 socket 的异步 IO 支持差、限制多,没法真正撑起 Proactor;
  • epoll 足够强:Linux 的 epoll 已经能高效支撑百万连接(详见「epoll 原理」那道题),Reactor + epoll 这套同步方案在 Linux 上表现优异,够用且成熟。

Windows 的 IOCP(IO Completion Port) 是成熟的异步 IO 机制,天然适合 Proactor,所以 Windows 高性能服务器常用 Proactor。

补充:Linux 新的 io_uring 提供了真正高效的异步 IO 接口,正在让 Linux 上的 Proactor 风格成为可能,是未来方向。

四、编程复杂度与「模拟 Proactor」

  • Reactor 的编程:你要处理「就绪事件 → 自己读 → 处理 → 自己写」,读写缓冲区的管理在应用层,稍繁琐但可控;
  • Proactor 的编程:你发起异步操作、注册完成回调,缓冲区在发起时就交给内核,逻辑上更「异步」。

由于 Linux AIO 不给力,一些库会用 Reactor「模拟」Proactor 的编程体验——底层还是 epoll(Reactor),但在应用层封装成「发起读 → 完成回调」的异步 API(如 Boost.Asio 在 Linux 上就是用 epoll 模拟 Proactor 接口)。这样开发者写的是 Proactor 风格代码,底层跑的是 Reactor。

五、如何回答「用哪个」

面试问「Reactor 和 Proactor 选哪个」,可以这样答:

  • 看平台:Linux 上因为 AIO 不成熟,主流是 Reactor + epoll(Netty、Redis、Nginx);Windows 上 IOCP 成熟,适合 Proactor
  • 看成熟度:Reactor 生态成熟、可控、久经考验;Proactor 编程更简洁但依赖底层异步 IO 支持;
  • 趋势:Linux 的 io_uring 正在补齐异步 IO,未来 Proactor 风格会更可行。

结论通常是:在 Linux 做高并发,用 Reactor(epoll);理解 Proactor 的思想,知道它基于异步 IO、更适合 Windows/未来的 io_uring。

六、常见误区与追问

考点正确口径
Reactor通知“可以读/写了”,应用自己执行 IO
Proactor提交 IO 操作,完成后通知应用处理结果
典型差异Reactor 面向就绪事件,Proactor 面向完成事件
Reactor:
event loop -> readable -> application read()

Proactor:
application submit read
kernel completes read
callback receives data

Reactor 是“你可以去做了”,Proactor 是“我做完了,你处理结果”。

  • 误区:Reactor 和 Proactor 只是名字不同。 它们关注的事件语义不同,一个是就绪,一个是完成。
  • 误区:epoll 就是 Proactor。 epoll 通知 fd 就绪,应用仍要自己 read/write,更符合 Reactor。
  • 误区:Proactor 一定全面优于 Reactor。 Proactor 依赖系统异步 IO 能力,模型更复杂,并不总是更简单或更快。
  • 追问:Windows IOCP 属于哪类? IOCP 更接近 Proactor,应用提交异步 IO,完成后收到完成事件。
  • 追问:为什么 Java NIO 常说 Reactor? Selector 通知通道就绪,业务线程再执行读写和处理。
  • 追问:两者对业务代码有什么影响? Reactor 要小心非阻塞读写循环,Proactor 更像处理已经完成的 IO 结果。

七、加强记忆

Reactor 和 Proactor 都是事件驱动高并发模型,区别是基于「就绪」还是「完成」:Reactor 基于同步 IO(epoll),事件就绪时通知、应用自己读写拷贝数据(「能读了你来读」);Proactor 基于异步 IO(AIO/IOCP),内核把 IO 全做完(含拷贝)后通知完成(「读完了给你」)。Linux 因原生 AIO 不成熟,主流用 Reactor + epoll(Netty/Redis);Windows IOCP 适合 Proactor;io_uring 是 Linux 异步的未来方向。