Skip to content

并发系统: Reactor 与 Proactor 深度解析 #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
htoooth opened this issue Apr 29, 2025 · 0 comments
Open

并发系统: Reactor 与 Proactor 深度解析 #6

htoooth opened this issue Apr 29, 2025 · 0 comments

Comments

@htoooth
Copy link
Owner

htoooth commented Apr 29, 2025

Reactor 与 Proactor 模式深度解析

I. 引言:并发 I/O 的挑战

A. I/O 操作的普遍性与挑战

在现代计算系统中,输入/输出(I/O)操作无处不在,涵盖了网络通信、磁盘文件访问、数据库交互以及进程间通信等多种场景 1。然而,I/O 操作的速度通常远低于中央处理器(CPU)的执行速度,这种固有的速度差异对构建高响应性、高可扩展性的应用程序构成了重大挑战,尤其是在需要同时处理大量客户端连接的服务器应用中 2。如何有效地管理 I/O 操作,避免其成为系统瓶颈,是并发系统设计的核心问题之一。

B. I/O 模型的演进

为了应对 I/O 延迟带来的挑战,多种 I/O 处理模型应运而生,并在实践中不断演进:

  1. 阻塞 I/O (Blocking I/O): 这是最简单直接的模型。应用程序线程发起一个 I/O 系统调用(如 read(), write(), accept()),然后该线程将被阻塞,直到操作完成 1。这种模型编程简单,逻辑清晰,但其同步阻塞的特性严重限制了并发能力,因为线程在等待 I/O 时无法执行其他任务。
  2. 每连接/请求一个线程 (Thread-per-Connection/Request): 为了克服阻塞 I/O 的并发限制,一种常见的策略是为每个客户端连接或请求分配一个独立的线程(或进程)进行处理 2。这种模型允许并发处理多个连接,但随着连接数的增加,其弊端也日益凸显。创建和管理大量线程会消耗巨大的系统资源(尤其是内存,用于存储线程栈 7)并导致显著的上下文切换开销 2。上下文切换涉及保存和恢复 CPU 状态(寄存器、程序计数器等),可能还需要切换内存地址空间(进程切换比线程切换开销更大,因为线程共享地址空间 16),并可能导致缓存(CPU Cache, TLB)失效,进一步降低性能 16。这种模型的可扩展性因此受到严重限制,常常遭遇所谓的“C10k 问题”(即难以高效处理上万并发连接)3。
  3. 非阻塞同步 I/O (Non-blocking Synchronous I/O): 在此模型下,I/O 系统调用(需设置为非阻塞模式)会立即返回,无论操作是否完成 1。如果操作可以立即完成,则返回成功;如果无法立即完成(例如,没有数据可读或缓冲区已满),则返回一个特定的错误码(如 EWOULDBLOCK 或 EAGAIN)。这种方式避免了线程的阻塞,但应用程序需要主动、反复地检查(轮询)I/O 操作是否可以进行(即“忙等待”,busy-waiting),这会浪费 CPU 资源 1。更有效的方法是结合事件通知机制(如 select, poll, epoll),仅在 I/O 资源就绪时才进行操作,这便引出了 Reactor 模式 1。
  4. 异步 I/O (Asynchronous I/O, AIO): 在异步 I/O 模型中,应用程序发起一个 I/O 操作后立即返回,无需等待操作完成 5。操作系统(或底层库)在后台负责执行该 I/O 操作。当操作完成时,操作系统会通过某种机制(如回调函数、信号、完成端口事件)通知应用程序。这种模型将 I/O 操作的发起和完成处理解耦,是 Proactor 模式的基础。

从阻塞 I/O 到非阻塞同步 I/O,再到异步 I/O 的演进,反映了在编程简易性与系统性能/可扩展性之间的权衡。阻塞 I/O 最简单但性能最差;每连接线程模型提高了并发性但资源消耗和上下文切换开销巨大;非阻塞同步 I/O 避免了线程阻塞但需要额外的机制(如事件通知)来管理;异步 I/O 将 I/O 执行完全委托给操作系统,潜力最大但也引入了不同的编程范式(基于完成通知)。

C. 高级并发模式的需求

为了在管理并发 I/O 的复杂性与实现高性能、高可扩展性之间取得平衡,Reactor 和 Proactor 这两种高级事件处理模式应运而生 2。它们提供了一种结构化的方法,通常使用单个线程或少量线程来处理大量的并发 I/O 事件(分别是就绪事件或完成事件),从而有效克服了简单模型的局限性 2。它们的核心思想是将连接(或请求)与处理线程解耦,通过事件多路复用(demultiplexing)和分发(dispatching)来管理并发,直接应对 C10k 问题所暴露的资源耗尽和上下文切换开销瓶颈 2。

D. 报告范围

本报告旨在从技术专家的视角,深入剖析和比较 Reactor 与 Proactor 这两种核心的并发 I/O 设计模式。报告将详细阐述它们的体系结构、工作流程、关键差异、底层操作系统机制依赖、平台特定实现、优缺点以及适用场景,并最终总结它们的设计哲学及其对应用程序架构的影响。

II. Reactor 模式:同步事件多路分发

A. 核心概念与设计哲学

Reactor 模式是一种基于事件驱动的并发设计模式,其核心在于处理I/O 就绪 (Readiness) 事件 5。它的基本设计哲学可以概括为:“当你可以进行某个操作(如读、写、接受连接)时通知我,然后由我(应用程序)来执行这个操作” 46。该模式依赖于一个同步的事件多路分发机制,该机制能够同时监听多个 I/O 句柄(Handles),并在其中任何一个句柄准备好进行特定操作时通知应用程序 2。尽管 Reactor 模式本身可以利用多线程进行扩展(例如,将事件处理分派给线程池),但其经典实现的核心事件循环通常运行在单个线程中,通过高效地交错处理来自不同源的就绪事件来实现并发 2。

B. 架构组件 2

Reactor 模式主要由以下几个关键组件构成:

  1. 句柄 (Handle): 代表操作系统管理的、能够产生 I/O 事件的资源 2。在网络编程场景下,句柄通常是文件描述符(File Descriptor),例如套接字(Socket)、管道(Pipe)等。它们是 I/O 事件的来源。
  2. 同步事件多路分发器 (Synchronous Event Demultiplexer / Event Notifier): 这是 Reactor 模式的核心机制,负责同时监视多个句柄上的事件 1。它提供了一个阻塞式的系统调用(如 POSIX 的 select, poll, Linux 的 epoll, BSD/macOS 的 kqueue),该调用会一直等待,直到至少一个被监视的句柄准备好进行应用程序所请求的 I/O 操作(例如,可读、可写、有新连接待接受)时才返回 1。现代的机制如 epoll 和 kqueue 相较于传统的 select 和 poll 具有更好的可扩展性,因为它们避免了对所有被监视句柄的线性扫描,通常具有 O(1) 或 O(就绪句柄数) 的时间复杂度,使得 Reactor 模式能够高效处理大量并发连接 35。这种操作系统层面的优化对于 Reactor 模式在实践中成功处理数千甚至数万连接至关重要 3。
  3. 事件处理器 (Event Handler / Request Handler): 这是由应用程序定义的组件,负责处理特定句柄上的特定类型事件 2。通常,所有的事件处理器都实现一个共同的接口(例如,包含一个 handle_event 方法),以便 Reactor 可以统一地调用它们 2。具体的事件处理器(Concrete Event Handler)包含了实际的应用程序逻辑,例如从套接字读取数据、解析客户端请求、接受新的网络连接等 41。
  4. 反应器 (Reactor / Initiation Dispatcher): 这是模式的中心协调者,负责管理事件处理器及其关联句柄的注册 3。Reactor 运行事件循环 (Event Loop),在循环中调用同步事件多路分发器来等待事件。一旦接收到就绪通知,Reactor 就根据就绪的句柄查找对应的事件处理器,并调用其 handle_event 方法来处理事件 1。

C. 详细工作流程 1

Reactor 模式的工作流程通常如下:

  1. 注册 (Registration): 应用程序组件(具体的事件处理器)向 Reactor 注册,指明它感兴趣的句柄以及希望处理的事件类型(如 READ, WRITE, ACCEPT)2。Reactor 内部维护一个注册表(通常是哈希表或类似结构)来存储这些句柄到处理器的映射关系。
  2. 事件循环 (Event Loop): Reactor 启动并进入其主事件循环。在循环的开始,它调用同步事件多路分发器的等待函数(如 select(), poll(), epoll_wait()),传入所有已注册的句柄及其关注的事件类型 1。这个调用是阻塞的,Reactor 线程在此暂停,等待事件发生。
  3. 事件多路分发 (Demultiplexing): 当一个或多个句柄上发生所关注的事件(即句柄变为就绪状态)时,同步事件多路分发器从阻塞状态返回 1。它通常会返回一个就绪句柄的集合以及每个句柄上发生的具体事件类型。
  4. 分发 (Dispatching): Reactor 遍历返回的就绪句柄集合。对于每一个就绪的句柄,Reactor 在其内部注册表中查找对应的事件处理器 2。
  5. 处理器调用 (Handler Invocation): Reactor 调用找到的事件处理器的 handle_event 方法,并将就绪的句柄和事件类型作为参数传递给它 1。
  6. 同步 I/O 执行 (Synchronous I/O Execution): 在 handle_event 方法内部,事件处理器执行实际的 I/O 操作 2。例如,如果事件是 READ 就绪,处理器会调用 read() 或 recv() 从句柄读取数据;如果是 ACCEPT 就绪,则调用 accept() 接受新连接。关键在于,此时执行的 I/O 操作是同步的,但在逻辑上是非阻塞的。因为事件多路分发器已经确认了该句柄处于就绪状态,所以这个 I/O 调用预期会立即完成,而不会导致调用线程(即 Reactor 的事件循环线程)阻塞 2。
  7. 应用逻辑处理 (Application Logic): 事件处理器在完成 I/O 操作后,继续执行相关的应用逻辑,例如处理接收到的数据、响应客户端请求或设置新连接的处理器。
  8. 返回控制权 (Return): 事件处理器完成其任务后,将控制权返回给 Reactor 的事件循环 1。Reactor 继续处理下一个就绪事件(如果有的话),或者在处理完所有当前就绪事件后,返回到事件循环的起点,再次调用同步事件多路分发器等待新的事件。

关于 Reactor 中 “同步” 的理解需要特别注意。它指的是事件分发和处理的机制是同步的——即 Reactor 分派一个事件给处理器,处理器必须完成(包括其内部的 I/O 操作)后才返回,然后 Reactor 才能处理下一个事件。然而,处理器内部执行的 I/O 调用本身,由于事先经过了就绪性检查,因此不会阻塞线程。这与 Proactor 模式中由操作系统异步执行 I/O 的方式形成了对比。

D. 并发性考量

基础的 Reactor 模式是单线程的 2。它通过在一个线程内快速地交错处理来自多个 I/O 源的事件来实现并发,而不是通过并行执行。这种单线程模型的并发能力受限于事件处理器的执行时间。如果某个事件处理器的 handle_event 方法执行时间过长,或者意外地执行了阻塞操作(例如,访问数据库、执行复杂的计算),它就会阻塞整个事件循环,导致其他就绪的事件无法得到及时处理,从而影响系统的响应性 2。

为了解决这个问题并利用多核处理器的优势,Reactor 模式可以进行扩展:

  • Reactor + Worker 线程池 (Reactor-Executor Pattern): Reactor 仍然负责事件的检测和分发,但它不直接调用事件处理器的 I/O 操作和业务逻辑,而是将任务(包含就绪的句柄和事件信息)提交给一个工作线程池 2。工作线程从任务队列中取出任务并执行耗时的 I/O 操作和业务逻辑。这样,Reactor 的主事件循环线程可以迅速返回并继续检测其他事件,避免了阻塞。但这引入了线程同步的复杂性(如任务队列的同步访问)。
  • 多 Reactor (Multireactor): 可以创建多个 Reactor 实例,每个实例运行在独立的线程中,并负责监听一部分 I/O 句柄 2。进入的连接或请求可以被分发到不同的 Reactor 线程上。这种方式可以更好地利用多核 CPU,提高整体吞吐量,并提供一定的容错性(一个 Reactor 线程失败不影响其他 Reactor)。

事件处理器的执行时间对于基础 Reactor 模型的性能至关重要。长时间运行或阻塞的处理逻辑会成为整个系统的瓶颈 52。因此,开发者必须仔细设计事件处理器,确保其快速且非阻塞,或者采用更复杂的多线程 Reactor 变体来处理耗时任务,但这会增加同步开销和实现的复杂性 2。

III. Proactor 模式:异步操作完成

A. 核心概念与设计哲学

Proactor 模式是一种同样基于事件驱动的并发设计模式,但它与 Reactor 的核心区别在于其驱动力来源。Proactor 模式利用操作系统提供的真异步 I/O (Asynchronous I/O, AIO) 功能 5,其设计哲学可以概括为:“请帮我执行这个 I/O 操作,操作完成后再通知我” 5。在这种模式下,应用程序主动发起 (initiate) 一个异步 I/O 操作,然后可以立即返回并继续执行其他任务。实际的 I/O 操作由操作系统(或底层异步机制)在后台完成。当操作完成后,系统会生成一个完成事件 (Completion Event),并通过某种机制通知应用程序。Proactor 模式的核心在于处理这些完成事件。这种模式天然地将 I/O 操作的发起与完成处理解耦,使得应用程序线程可以从耗时的 I/O 等待中解放出来 36。

B. 架构组件 33

Proactor 模式通常包含以下组件:

  1. 主动发起者 (Proactive Initiator): 应用程序中的组件,负责调用异步操作接口来发起一个异步 I/O 请求(如 async_read, async_write)34。发起者需要提供执行操作所需的所有参数,包括目标句柄、用于数据传输的缓冲区 (Buffer) 以及一个用于处理操作完成结果的完成处理器 (Completion Handler)。
  2. 异步操作处理器 (Asynchronous Operation Processor): 通常指操作系统内核或其提供的异步 I/O 子系统,负责在后台实际执行由发起者请求的异步 I/O 操作 34。例如,Windows 的 I/O 完成端口 (IOCP) 机制和某些 POSIX AIO 实现(如 Linux 内核 AIO 或 io_uring)扮演了这个角色 35。它接管 I/O 任务,执行完毕后生成完成事件。
  3. 异步操作 (Asynchronous Operation): 指由发起者请求的具体非阻塞操作,例如异步读取、异步写入、异步接受连接等 34。这些操作的特点是调用后立即返回,执行过程由异步操作处理器在后台管理。
  4. 完成处理器 (Completion Handler): 由应用程序定义的对象或函数,用于处理异步操作完成后的结果 33。它通常实现一个特定的接口(如包含 handle_read_complete, handle_write_complete 等方法)。当 Proactor 分发一个完成事件时,会调用关联的完成处理器的相应方法。
  5. 完成事件队列 (Completion Event Queue): 一个用于存储已完成的异步操作结果的队列 34。当异步操作处理器完成一个操作后,会将包含操作结果(如成功/失败状态、传输的字节数、错误码等)的完成事件放入此队列。这个队列通常由操作系统内核或 Proactor 实现自身来管理。例如,Windows IOCP 就维护了这样一个队列。
  6. 前摄器 (Proactor / Completion Dispatcher): 这是 Proactor 模式的核心调度组件 34。它的职责是从完成事件队列中取出 (dequeue) 完成事件,并根据事件信息找到对应的完成处理器,然后调用该处理器的相应方法来处理完成结果。Proactor 通常会管理一个或多个线程,这些线程负责阻塞等待并处理完成事件队列中的事件。例如,Boost.Asio 库中的 io_context 就扮演了 Proactor 的角色 56。

C. 详细工作流程 5

Proactor 模式处理一个异步 I/O 操作的典型流程如下:

  1. 发起操作 (Initiation): 主动发起者(应用程序代码)调用异步操作处理器(通常是操作系统提供的 API,如 ReadFile 或 WSARecv 配合 OVERLAPPED 结构,或 POSIX 的 aio_read)来启动一个异步 I/O 操作 33。发起者需要提供所有必要的参数,包括:
    • 目标句柄(如套接字文件描述符)。
    • 一个应用程序拥有的数据缓冲区(用于读取操作时接收数据,或用于写入操作时提供数据)。
    • 一个指向完成处理器的引用(或与之关联的标识)。
    • (可选)一个指向 Proactor (Completion Dispatcher) 的引用。 该调用是非阻塞的,它会立即返回,使得发起者线程可以继续执行其他任务 36。
  2. 异步执行 (Asynchronous Execution): 异步操作处理器(操作系统)接管 I/O 请求,并在后台执行实际的 I/O 操作 5。例如,如果是异步读,操作系统会等待数据到达,然后将数据直接读入应用程序提供的缓冲区;如果是异步写,操作系统会将应用程序缓冲区中的数据写入目标句柄。这个过程不会阻塞发起操作的应用程序线程。
  3. 完成通知 (Completion Notification): 当操作系统完成该异步 I/O 操作(无论成功还是失败)后,它会生成一个完成事件 34。这个事件包含了操作的结果信息(例如,成功/失败状态码、实际传输的字节数、关联的完成处理器标识等)。然后,操作系统将此完成事件放入与 Proactor 关联的完成事件队列中。
  4. 事件出队 (Event Dequeuing): Proactor 组件(通常在一个或多个专用线程中运行)负责监视完成事件队列 12。它会调用相应的系统函数(如 Windows 的 GetQueuedCompletionStatus 或 Linux AIO/io_uring 的 io_getevents)来阻塞等待队列中的事件。当队列中有事件时,Proactor 将其取出。
  5. 分发 (Dispatching): Proactor 检查取出的完成事件,并从中提取出关联的完成处理器信息 34。
  6. 处理器调用 (Handler Invocation): Proactor 调用该完成处理器的特定方法(例如,handle_read_complete 或 handle_write_complete),并将完成事件中的结果信息(如指向包含数据的缓冲区、传输字节数、错误码等)作为参数传递给该方法 33。
  7. 结果处理 (Result Processing): 完成处理器的方法被执行。应用程序代码在此处处理已完成的 I/O 操作的结果 5。例如,处理从缓冲区读取到的数据,或者检查写入操作是否成功。完成处理器在处理完当前结果后,可能会发起新的异步 I/O 操作(例如,读取下一批数据或发送响应),从而形成一个异步操作链,继续事件驱动的流程。

D. 并发性考量

Proactor 模式的并发性主要来源于两个方面:

  • 操作并行性: 操作系统可以同时处理多个由应用程序发起的异步 I/O 操作 36。应用程序无需为每个并发 I/O 操作创建单独的线程。
  • 处理并行性: Proactor 通常会使用一个(或多个)线程池来执行完成处理器中的代码 68。当多个 I/O 操作同时完成时,Proactor 可以将这些完成事件分发给线程池中的不同线程并行处理,从而提高完成事件的处理速度。

这种模型将繁重的 I/O 操作卸载给了操作系统,使得应用程序线程能够更专注于业务逻辑和发起新的操作,从而有可能实现更高的 CPU 利用率以及计算与 I/O 操作的有效重叠 36。并发的瓶颈通常转移到操作系统 AIO 子系统的效率以及完成处理器本身的执行效率上。

然而,Proactor 模式的实际性能和可扩展性高度依赖于底层操作系统提供的异步 I/O 实现的质量 36。一个高效的、内核级别的 AIO 实现(如 Windows IOCP 或 Linux io_uring)是发挥 Proactor 模式优势的关键。如果操作系统对 AIO 的支持不佳(例如,通过用户态线程池模拟异步,如传统的 glibc POSIX AIO 实现),那么 Proactor 模式可能无法带来预期的性能提升,甚至可能比精心设计的 Reactor 模式更差 12。

此外,Proactor 模式也带来了新的复杂性。应用程序需要仔细管理用于异步操作的缓冲区的生命周期,确保在 OS 使用期间它们保持有效且不被意外修改 58。同时,基于回调的异步完成机制(即控制流的反转)可能使得程序的逻辑跟踪和调试比同步代码更加困难 2。

IV. 对比分析:Reactor vs. Proactor

Reactor 和 Proactor 模式虽然都旨在解决高并发 I/O 问题,但它们在核心机制、职责划分、平台依赖和实现复杂性等方面存在显著差异。

A. 核心驱动力:就绪 vs. 完成 5

  • Reactor:I/O 就绪 (Readiness) 事件驱动。其核心是同步事件多路分发器(如 select, epoll),它通知应用程序:“某个句柄现在可以进行读/写/接受操作了,并且不会阻塞”。应用程序收到通知后主动执行该操作。其设计哲学是被动响应就绪状态
  • Proactor:I/O 操作完成 (Completion) 事件驱动。其核心是异步 I/O 操作和完成通知机制(如 AIO, IOCP, io_uring)。应用程序发起异步操作后,由操作系统执行,并在操作已经完成后通知应用程序:“你之前请求的读/写操作已经做完了,结果在这里”。其设计哲学是主动发起操作,被动接收完成结果

B. I/O 操作执行者:应用程序 vs. 操作系统 5

  • Reactor: I/O 操作(如 read(), write(), accept())是由应用程序的事件处理器 (Event Handler) 在收到就绪通知后执行的。操作系统仅负责通知就绪状态。
  • Proactor: I/O 操作是由异步操作处理器(通常是操作系统内核) 在后台执行的。应用程序仅负责发起异步请求和处理完成后的结果。

C. 同步 vs. 异步模型 2

  • Reactor: 主要处理同步 I/O 操作(尽管等待事件的过程是多路复用的,但操作本身在处理器内是同步执行的)。它依赖于同步的事件多路分发机制 (select, epoll 等)。事件处理是同步进行的,即处理器完成工作后才返回事件循环。
  • Proactor: 处理异步 I/O 操作。它依赖于操作系统提供的异步 I/O API(如 IOCP, AIO, io_uring)。操作的发起和完成是解耦的,完成事件的处理通常也是异步的(由 Proactor 的线程池处理)。

D. 数据流向与处理 5

  • Reactor: 在读操作中,事件处理器在收到就绪通知后,需要主动从内核缓冲区读取数据到应用程序的缓冲区。在写操作中,处理器将应用程序缓冲区的数据写入内核缓冲区。数据是在就绪时由应用程序主动传输的。
  • Proactor: 在读操作中,应用程序在发起异步请求时提供一个缓冲区,操作系统完成读取后将数据直接放入该缓冲区,完成处理器直接处理这个已填充好的缓冲区。在写操作中,应用程序提供包含待写入数据的缓冲区,操作系统负责将其写入。数据是在发起时提供(写)或在完成时已准备好(读)。

E. 并发模型与线程使用

  • Reactor: 基本模型通过事件交错在单线程内实现并发。可以通过将事件处理任务分派给线程池来引入并行处理,但这增加了复杂性。主要并发点在于同时监听多个句柄。
  • Proactor: 并发性主要来自操作系统并行执行多个异步 I/O 操作的能力。应用程序通常使用一个(或多个)线程来调用 Proactor 的事件分发接口(等待完成事件),并将完成处理器的执行委托给 Proactor 管理的线程池。计算与 I/O 的重叠更为自然。

F. 实现复杂度与平台依赖性 2

  • Reactor:
    • 复杂度: 相对较低,尤其是使用 select/poll 的基本实现。主要复杂点在于确保事件处理器不阻塞事件循环,以及在引入多线程时的同步问题。
    • 平台依赖: 对 I/O 多路复用 API(select, poll, epoll, kqueue)的依赖。select/poll 具有广泛的 POSIX 兼容性,使得 Reactor 模式具有较好的可移植性 43。epoll (Linux) 和 kqueue (BSD/macOS) 性能更优,但特定于平台。
  • Proactor:
    • 复杂度: 通常更高 2。需要处理异步流程控制(回调、Future/Promise 等)、管理数据缓冲区的生命周期 58,以及应对可能的平台 AIO 差异和陷阱。调试也更困难 2。
    • 平台依赖: 高度依赖操作系统对真异步 I/O (AIO) 的支持 36。
      • Windows: IOCP 提供了强大且高效的 AIO 支持,是 Proactor 模式的理想平台 35。
      • POSIX AIO: 标准存在,但实现质量参差不齐。特别是 glibc 的实现,通常基于用户态线程池模拟异步 12,性能不佳且扩展性差,对网络套接字的支持尤其有限或不存在 13。这使得在许多 Unix-like 系统上实现高性能 Proactor 非常困难。
      • Linux Native AIO (io_submit等): 内核级 AIO,比 POSIX AIO 实现更接近底层,但历史上主要面向磁盘 I/O,且通常要求 O_DIRECT(绕过页缓存),对网络套接字支持有限,并且可能在元数据操作时阻塞 12。
      • Linux io_uring: 是 Linux 内核中较新的 AIO 接口,旨在提供高效、真正的异步 I/O,支持文件和网络套接字,并通过共享内存环(Ring Buffer)减少系统调用开销 38。它的出现极大地提升了 Proactor 模式在 Linux 平台上的可行性和性能潜力,可能成为 epoll 的有力竞争者或替代者,尽管其性能表现可能依赖于具体工作负载 67。
    • 模拟 Proactor (Emulated Proactor): 由于 POSIX 平台 AIO 支持的不足,许多跨平台库(如 Boost.Asio 56)在这些系统上会模拟 Proactor 模式。它们对外提供 Proactor 风格的异步 API(发起操作 + 完成回调),但在内部使用 Reactor 机制(如 epoll)来检测 I/O 就绪。当检测到就绪时,库本身(而不是应用程序的 Handler)执行非阻塞的同步 I/O 操作,完成后再调用应用程序提供的完成回调 33。这种方式提供了 API 的一致性,但其性能特征更接近 Reactor,无法获得真 AIO 带来的 I/O 与计算重叠的全部优势。

选择 Reactor 还是 Proactor 往往首先受到目标操作系统的 I/O 能力的制约。在缺乏高效、可靠的真 AIO 支持的平台上(历史上大部分 Unix-like 系统对网络 AIO 支持不佳),Reactor(尤其是基于 epoll 或 kqueue 的)通常是更实用、更可预测的选择。只有在操作系统提供了像 Windows IOCP 或 Linux io_uring 这样强大的 AIO 基础时,Proactor 的性能优势才能真正体现出来。

G. Reactor 与 Proactor 特性对比表

特性 Reactor Proactor
核心驱动事件 I/O 就绪 (Readiness) (select, epoll) I/O 完成 (Completion) (AIO, IOCP, io_uring)
I/O 操作执行者 应用程序 (事件处理器) 操作系统 (异步操作处理器)
I/O 调用类型 同步 (但基于就绪保证非阻塞) 异步
处理器角色 执行 I/O, 处理数据 处理已完成的 I/O 结果
数据流 处理器从内核读/写数据 OS 读/写数据到/从应用缓冲区
并发模型 事件交错 (基础); 线程池 (高级) OS 管理的异步操作; 处理器线程
实现复杂度 相对较低 (基础模型) 相对较高 (异步流, 缓冲区管理)
可移植性 较高 (尤其 select/poll) 较低 (高度依赖 OS AIO 支持)
平台范例 epoll (Linux), kqueue (BSD), select IOCP (Windows), io_uring (Linux), POSIX AIO (部分)
设计哲学 “你准备好了吗?” (被动响应就绪) “我做完了。” (主动发起, 被动接收完成)

V. 评估:优缺点与适用场景

对 Reactor 和 Proactor 模式的评估需要考虑其各自的优势、劣势以及最适合的应用场景。选择哪种模式是一个重要的架构决策,受到性能需求、平台特性、开发复杂度和可维护性等多方面因素的影响。

A. Reactor 模式评估

  • 优势:
    • 可移植性 (Portability): 由于依赖的 select 和 poll 系统调用在几乎所有类 Unix 系统上都可用,Reactor 模式具有良好的跨平台性 43。即使使用性能更优的 epoll (Linux) 或 kqueue (BSD/macOS),也能覆盖主流服务器平台。这使得基于 Reactor 的应用更容易部署到不同环境中 2。
    • 概念相对简单 (Conceptual Simplicity): 基础的单线程 Reactor 模型,其事件循环和顺序处理事件的逻辑相对容易理解和实现 3。开发者可以专注于编写事件处理器内的逻辑。
    • 细粒度控制 (Control): 应用程序通过事件处理器直接执行 I/O 操作,因此对操作的时机和方式有更精细的控制。
    • 资源效率 (Resource Efficiency): 相比于为每个连接创建一个线程的模型,Reactor 使用固定数量(通常是一个或少量)的线程来处理所有连接,显著减少了线程创建和上下文切换的开销,提高了资源利用率 41。
  • 劣势:
    • 阻塞风险 (Potential for Blocking): 这是 Reactor 模式最主要的缺点。如果事件处理器执行了耗时过长的计算任务,或者意外地调用了阻塞式 I/O(例如,同步数据库查询),将会阻塞整个事件循环线程,导致其他所有待处理的事件(即使对应的句柄已经就绪)无法被及时处理,严重影响应用的响应性和吞吐量 2。这要求事件处理器的实现必须非常高效且严格非阻塞。
    • 可扩展性瓶颈 (Scalability Limits): 在单线程模型中,所有事件处理是串行执行的,这限制了系统在多核 CPU 上的扩展能力 43。即使使用 epoll 或 kqueue 提高了事件检测的效率,处理器的串行执行仍然可能成为瓶颈,尤其是在处理器任务本身是 CPU 密集型的情况下。
    • 多线程复杂性 (Complexity in Multi-threading): 为了解决阻塞风险和利用多核,可以将事件处理分派给工作线程池。但这引入了额外的复杂性,包括线程同步(如任务队列的互斥访问)、线程管理以及 Reactor 线程与工作线程之间的通信 2。
  • 适用场景 / 用例:
    • 需要处理大量并发连接,但每个连接上的 I/O 操作相对短暂且处理器逻辑不复杂的场景,例如传统的 HTTP 服务器、代理服务器、聊天服务器等 1。
    • 图形用户界面 (GUI) 的事件循环,用于响应用户的交互事件(键盘、鼠标点击等)。
    • 当跨平台可移植性是重要考虑因素时。
    • 许多流行的网络框架和服务都基于 Reactor 模式或其变体实现,例如 Node.js (其底层的 libuv 库实现了 Reactor 模式) 1、Netty (可以选择 Reactor 模式)、Python 的 asyncio 库等。

B. Proactor 模式评估

  • 优势:
    • 高性能潜力 (Higher Performance Potential): 在拥有高效、真正异步 I/O 支持的操作系统上(如 Windows IOCP, Linux io_uring),Proactor 模式通常能实现更高的 I/O 吞吐量和更低的延迟 36。这是因为它将 I/O 操作完全委托给操作系统,使得应用程序线程可以与 I/O 操作并行执行,实现了计算与 I/O 的有效重叠 36。
    • 更好的并发性 (Improved Concurrency): 操作系统可以并行处理大量的异步 I/O 请求,而应用程序端只需要少量线程来发起请求和处理完成事件,从而支持极高的并发度 36。
    • 关注点分离 (Decoupling): 将 I/O 操作的执行(由 OS 负责)与操作结果的处理(由应用程序的完成处理器负责)清晰地分离开来 36。
  • 劣势:
    • 平台强依赖性 (Platform Dependency): Proactor 模式的性能和可行性极度依赖于底层操作系统对真异步 I/O 的支持 36。在缺乏良好 AIO 支持的平台上(如传统 POSIX AIO 对网络的支持普遍较差),Proactor 模式可能无法带来性能优势,甚至可能因为模拟 AIO 的开销而表现更差。
    • 实现复杂性 (Complexity): Proactor 模式通常被认为比 Reactor 更复杂 2。开发者需要处理异步控制流(回调函数、Promise、Future 等,可能导致“回调地狱”),需要仔细管理用于异步操作的数据缓冲区的生命周期(确保在 OS 使用期间有效)58,并且异步程序的调试通常比同步程序更困难 2。
    • 资源管理 (Resource Management): 需要预先分配并管理好用于异步读写的缓冲区,这可能比 Reactor 按需读写需要更精心的内存管理策略 58。
    • 调度控制较弱 (Less Control over Scheduling): 实际 I/O 操作的执行调度由操作系统决定,应用程序对其优先级和精确时序的控制力相对较弱 43。
  • 适用场景 / 用例:
    • 对 I/O 吞吐量和并发性能有极致要求的应用,并且目标平台提供了高效的异步 I/O 支持(例如,Windows 平台上的高性能网络服务器、文件服务器;或者最新 Linux 内核上的高性能存储或网络应用,利用 io_uring)38。
    • 应用程序需要在执行 I/O 操作的同时进行大量的 CPU 计算,Proactor 模式有助于实现两者的重叠。
    • 一些现代网络框架和库提供了 Proactor 模式的实现或接口,如 Boost.Asio (在 Windows 上使用 IOCP,在其他平台可模拟) 56 和.NET 的异步 I/O 模型。

历史上,由于 POSIX AIO 对网络套接字的支持不完善或效率低下 53,许多跨平台库(如 Asio)在 Unix-like 系统上采用“模拟 Proactor”的方式 33。这种模拟提供了 Proactor 风格的异步 API,但在底层仍然使用 Reactor 机制(如 epoll)来实现。虽然这统一了编程模型,但并不能带来真 AIO 的性能优势。然而,Linux io_uring 的出现正在改变这一局面,它为 Linux 平台提供了强大、通用的真 AIO 基础,使得 Proactor 模式成为 Linux 上一个越来越有吸引力的高性能选择 38。

最终的选择取决于具体场景下的权衡。如果追求最广泛的平台兼容性和相对简单的实现,Reactor 可能是更稳妥的选择。如果目标平台(如 Windows 或现代 Linux)提供了强大的 AIO 支持,并且应用对并发性能有极高要求,那么克服 Proactor 的复杂性可能是值得的。

C. Reactor 与 Proactor 优缺点及场景对比表

方面 Reactor Proactor
优点 (Pros) 跨平台性好 (尤其 select/poll), 基础模型相对简单, I/O 控制精确 性能潜力高 (需良好 AIO 支持), 更好的 I/O/计算重叠, OS 处理 I/O
缺点 (Cons) 事件处理器易阻塞事件循环, 串行处理器限制扩展性, 多线程化复杂 实现复杂 (异步流/调试), 强依赖 OS AIO, 缓冲区管理复杂
最佳场景 中等并发, 短 I/O 任务, 需可移植性, GUI 事件循环 高并发, I/O 密集型, 平台有高效 AIO (IOCP, io_uring), 追求最大吞吐量
避免场景 处理器耗时长/阻塞, 需极限性能且平台 AIO 良好 平台 AIO 支持差, 追求简单性, 需严格 I/O 时序控制

VI. 结论:设计哲学与架构影响

Reactor 和 Proactor 模式代表了应对高并发 I/O 挑战的两种截然不同的设计哲学,它们深刻地影响着应用程序的架构、性能和开发复杂性。

A. 核心哲学回顾

两种模式的根本差异在于它们与 I/O 事件交互的方式:

  • Reactor 哲学:被动响应就绪 (Reactive Readiness)
    其核心思想是“当资源准备好时通知我,我来处理” 5。它采用一种反应式 (Reactive) 的姿态,等待操作系统发出“就绪”信号,然后由应用程序(事件处理器)接管并同步地执行 I/O 操作。控制权主要在应用程序手中,它决定何时以及如何进行 I/O。
  • Proactor 哲学:主动发起,被动接收完成 (Proactive Initiation, Passive Completion)
    其核心思想是“请帮我完成这个操作,完成后通知我” 5。它采用一种前摄式 (Proactive) 的姿态,由应用程序主动发起异步 I/O 请求,将 I/O 的执行完全委托给操作系统。应用程序随后可以执行其他任务,直到收到操作完成的通知,再由完成处理器处理结果。控制权在 I/O 执行期间转移给了操作系统。

这种哲学的差异直接导致了 I/O 执行责任的归属不同:Reactor 模式下,I/O 执行主体是应用程序的 Handler;而在 Proactor 模式下,I/O 执行主体是操作系统。

B. 对应用程序架构的影响

这两种不同的设计哲学对应用程序的整体架构产生了深远的影响:

  • Reactor 架构: 通常围绕一个中心事件循环 (Event Loop) 构建。应用程序的逻辑被分解为多个事件处理器 (Event Handlers),每个处理器负责响应特定句柄上的特定就绪事件。整个应用的控制流由 Reactor 的事件循环驱动。这种架构要求事件处理器的执行必须高效且非阻塞,以避免阻塞整个循环。状态管理可能需要在事件处理器之间传递或维护。它相对容易将现有的同步代码片段集成到事件处理器中(只要它们是非阻塞的)。
  • Proactor 架构: 倾向于形成一种基于异步操作链 (Chain of Asynchronous Operations) 的结构。应用程序逻辑通常表现为:发起一个异步操作,注册一个完成处理器;在完成处理器中处理结果,并可能发起下一个异步操作。控制流不再是单一的循环,而是分散在操作的发起和完成处理之间。这种架构天然地促进了 I/O 操作与计算任务的分离。然而,它要求开发者必须仔细管理异步流程(例如,使用回调、Promise/Future、async/await 等机制)和共享状态(尤其是传递给异步操作的缓冲区)的生命周期。

C. 性能、复杂度与可移植性的权衡总结

如前文所述,Reactor 和 Proactor 之间存在明显的权衡 39:

  • 性能: Proactor 在拥有高效 OS AIO 支持的平台上具有更高的性能潜力,因为它能更好地实现 I/O 与计算的重叠。Reactor 的性能受限于事件处理器的串行执行(在单线程模型中)和同步 I/O 的开销,但现代 demultiplexer (如 epoll) 已经非常高效。
  • 复杂度: Proactor 通常被认为更复杂,主要源于异步编程模型和资源管理的挑战。Reactor 的基础模型相对简单,但扩展到多线程以解决阻塞问题时也会引入复杂性。
  • 可移植性: Reactor 具有更好的可移植性,尤其是基于 select/poll 的实现。Proactor 的可移植性受到 OS AIO 支持的严重制约。

D. 现代趋势与未来方向

  • io_uring 的崛起: Linux io_uring 的出现和发展是近年来并发 I/O 领域最重要的进展之一 38。它提供了一个统一、高效、真正异步的 I/O 接口,支持文件、网络等多种操作,并能通过共享环缓冲区显著减少系统调用开销。这使得 Proactor 模式在 Linux 上成为一个极具吸引力的高性能选项,可能会在未来许多场景中取代基于 epoll 的 Reactor 实现。
  • 语言级异步支持: 现代编程语言(如 C++, Python, JavaScript, Rust, Go 等)普遍引入了 async/await 等语言级异步编程特性。这些特性通常作为上层抽象,其底层实现可能依赖于操作系统的 Reactor(如 epoll)或 Proactor(如 IOCP, io_uring)机制,或者结合使用用户态调度(如 Go 的 Goroutine 调度器)。这些语言特性旨在简化异步编程的复杂性,但理解底层的 I/O 模式对于性能调优和问题排查仍然至关重要。
  • 模式融合与抽象: 现代框架(如 Asio)倾向于提供统一的异步编程接口,并在底层根据平台特性选择最优的实现(真 Proactor 或基于 Reactor 的模拟 Proactor)56。这表明实践中可能会出现模式的融合或更高层次的抽象,隐藏底层的具体实现细节。

E. 最终专家视角

Reactor 和 Proactor 是解决并发 I/O 问题的两种强大但不同的架构模式。它们的设计哲学——是响应“就绪”还是响应“完成”——决定了它们的核心工作方式和对应用程序结构的影响。

选择哪种模式并非易事,而是一个需要综合考虑性能目标、目标运行平台特性(尤其是 AIO 支持情况)、团队对异步编程复杂性的接受程度以及应用具体 I/O 特点(如连接数量、请求频率、数据大小等)的架构决策。

  • Reactor 提供了一种相对健壮、可移植性好的方案,适用于广泛的并发场景,尤其是在缺乏强大 AIO 支持或需要精确控制 I/O 执行时。其主要挑战在于避免阻塞事件循环。
  • Proactor 则瞄准更高的性能上限,通过利用 OS 的异步能力实现计算与 I/O 的深度重叠。然而,它的优势高度依赖于平台支持,并且带来了更高的开发和调试复杂性。

随着像 io_uring 这样的底层技术的进步,Proactor 模式的应用前景正变得越来越广阔。然而,无论选择哪种模式,或者使用基于它们构建的更高级框架,深入理解其工作原理、优缺点以及与操作系统交互的细节,对于构建真正高效、可扩展和健壮的并发系统都是不可或缺的。

Works cited

  1. The reactor pattern - Packt+ | Advance your knowledge in tech, accessed April 28, 2025, https://www.packtpub.com/en-us/product/nodejs-design-patterns-9781785885587/chapter/1-dot-welcome-to-the-node-dot-js-platform-1/section/the-reactor-pattern-ch01lvl1sec04
  2. Reactor pattern - Wikipedia, accessed April 28, 2025, https://en.wikipedia.org/wiki/Reactor_pattern
  3. Understanding Reactor Pattern: Thread-Based and Event-Driven - DZone, accessed April 28, 2025, https://dzone.com/articles/understanding-reactor-pattern-thread-based-and-eve
  4. Patterns in C - Part 5: REACTOR - Adam Tornhill, accessed April 28, 2025, https://www.adamtornhill.com/Patterns%20in%20C%205,%20REACTOR.pdf
  5. Reactor vs Proactor - Parijat's Weblog - WordPress.com, accessed April 28, 2025, https://parijatmishra.wordpress.com/2008/01/08/reactor-vs-proactor/
  6. What is Reactor Pattern in Node.js - GeeksforGeeks, accessed April 28, 2025, https://www.geeksforgeeks.org/what-is-reactor-pattern-in-node-js/
  7. Processes and Threads | Operating Systems (OS) | Core Computer Science - workat.tech, accessed April 28, 2025, https://workat.tech/core-cs/tutorial/processes-and-threads-os-6iboki1s2y3t
  8. Thread in Operating System | GeeksforGeeks, accessed April 28, 2025, https://www.geeksforgeeks.org/thread-in-operating-system/
  9. Threads vs. Processes: How They Work Within Your Program - Backblaze, accessed April 28, 2025, https://www.backblaze.com/blog/whats-the-diff-programs-processes-and-threads/
  10. How memory management happens for process threads in one virtual address space?, accessed April 28, 2025, https://stackoverflow.com/questions/38555287/how-memory-management-happens-for-process-threads-in-one-virtual-address-space
  11. What resources are shared between threads? - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/1762418/what-resources-are-shared-between-threads
  12. Linux asynchronous file IO - kkourt, accessed April 28, 2025, https://kkourt.io/blog/2017/10-14-linux-aio.html
  13. io_submit: The epoll alternative you've never heard about - The Cloudflare Blog, accessed April 28, 2025, https://blog.cloudflare.com/io_submit-the-epoll-alternative-youve-never-heard-about/
  14. Context Switching in Operating System - GeeksforGeeks, accessed April 28, 2025, https://www.geeksforgeeks.org/context-switch-in-operating-system/
  15. Mastering Context Switching: Key to Peak Operating System Efficiency - Krish Space, accessed April 28, 2025, https://krishparekh.hashnode.dev/the-art-of-context-switching-maximizing-os-efficiency
  16. Thread context switch Vs. process context switch - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/5440128/thread-context-switch-vs-process-context-switch
  17. context switch between threads is less expensive that switching a new process - Hacker News, accessed April 28, 2025, https://news.ycombinator.com/item?id=36925275
  18. Difference between Thread Context Switch and Process Context Switch - GeeksforGeeks, accessed April 28, 2025, https://www.geeksforgeeks.org/difference-between-thread-context-switch-and-process-context-switch/
  19. Understanding Context Switching and Its Impact on System Performance - Netdata, accessed April 28, 2025, https://www.netdata.cloud/blog/understanding-context-switching-and-its-impact-on-system-performance/
  20. Context switch between kernel threads vs user threads - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/57410024/context-switch-between-kernel-threads-vs-user-threads
  21. What Is Context Switching in Operating System | LambdaTest, accessed April 28, 2025, https://www.lambdatest.com/blog/context-switching/
  22. Context switch - Wikipedia, accessed April 28, 2025, https://en.wikipedia.org/wiki/Context_switch
  23. Understanding overhead cost of context switching - Unix & Linux Stack Exchange, accessed April 28, 2025, https://unix.stackexchange.com/questions/681096/understanding-overhead-cost-of-context-switching
  24. Measuring context switching and memory overheads for Linux threads - Eli Bendersky, accessed April 28, 2025, https://eli.thegreenplace.net/2018/measuring-context-switching-and-memory-overheads-for-linux-threads/
  25. Why is it quicker to switch between threads than to switch between processes and share data between them? - Super User, accessed April 28, 2025, https://superuser.com/questions/618136/why-is-it-quicker-to-switch-between-threads-than-to-switch-between-processes-and
  26. Difference Between Thread Context Switch and Process Context Switch - Tutorialspoint, accessed April 28, 2025, https://www.tutorialspoint.com/difference-between-thread-context-switch-and-process-context-switch
  27. What is the CPU's role in managing context switching in multitasking? - Backup Education, accessed April 28, 2025, https://backup.education/showthread.php?tid=4304
  28. Process Threads & Context switching In Os - YouTube, accessed April 28, 2025, https://www.youtube.com/watch?v=hL52SXe4TDE
  29. What does Java thread context switching mean ? : r/java - Reddit, accessed April 28, 2025, https://www.reddit.com/r/java/comments/mlyctq/what_does_java_thread_context_switching_mean/
  30. More threads imply more context switching? Is this true for the Linux Kernel?, accessed April 28, 2025, https://stackoverflow.com/questions/57620590/more-threads-imply-more-context-switching-is-this-true-for-the-linux-kernel
  31. How can goroutines be more scalable than kernel threads, if the kernel threads only use a few pages of physical memory? : r/golang - Reddit, accessed April 28, 2025, https://www.reddit.com/r/golang/comments/117a4x7/how_can_goroutines_be_more_scalable_than_kernel/
  32. Operating System Design and Implementation, accessed April 28, 2025, https://people.cs.nycu.edu.tw/~ttyeh/course/2022_Spring/IOC5226/slide/lecture-10.pdf
  33. I/O Event Handling Design Patterns, accessed April 28, 2025, https://wiesen.github.io/post/io-event-handling-design-patterns/
  34. Proactor pattern - Wikipedia, accessed April 28, 2025, https://en.wikipedia.org/wiki/Proactor_pattern
  35. Note on Async IO Programming - GitHub, accessed April 28, 2025, https://gist.github.com/chaelim/e19bb603fb20a912acce54e086ffe3d5
  36. www.dre.vanderbilt.edu, accessed April 28, 2025, https://www.dre.vanderbilt.edu/~schmidt/PDF/proactor.pdf
  37. pyarali.proactor.pdf - The Hillside Group, accessed April 28, 2025, https://hillside.net/plop/plop97/Proceedings/pyarali.proactor.pdf
  38. A Universal I/O Abstraction for C++ - cor3ntin, accessed April 28, 2025, https://cor3ntin.github.io/posts/iouring/
  39. CppCon 2017: Sean Bollin “Reactor vs. Proactor” - YouTube, accessed April 28, 2025, https://www.youtube.com/watch?v=iMRbm32O0ws
  40. How to use the Linux AIO feature - GitHub, accessed April 28, 2025, https://github.com/littledan/linux-aio
  41. Reactor Pattern in Java: Mastering Non-blocking Event-Driven Architectures, accessed April 28, 2025, https://java-design-patterns.com/patterns/reactor/
  42. Reactor-Executor Pattern: A Deep Dive – Murat Genc, accessed April 28, 2025, https://gencmurat.com/en/posts/reactor-executer-pattern/
  43. Reactor and Proactor - DidaWiki, accessed April 28, 2025, https://didawiki.cli.di.unipi.it/lib/exe/fetch.php/magistraleinformatica/tdp/tpd_reactor_proactor.pdf
  44. Using Generative Design Patterns to Develop Network Server Applications - Department of Computing Science, accessed April 28, 2025, https://webdocs.cs.ualberta.ca/~duane/publications/pdf/2005hips.pdf
  45. Comparing Two High-Performance I/O Design Patterns - Artima, accessed April 28, 2025, https://www.artima.com/articles/comparing-two-high-performance-io-design-patterns
  46. reactor vs proactor - java - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/11859332/reactor-vs-proactor
  47. www.dre.vanderbilt.edu, accessed April 28, 2025, https://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf
  48. The reactor pattern - The Magic Of Coding, accessed April 28, 2025, https://themagicofcoding.com/blogs/nodejs/the-reactor-pattern/
  49. 3 Event Handling Patterns, accessed April 28, 2025, http://www.dre.vanderbilt.edu/~schmidt/POSA/POSA2/event-patterns.html
  50. kasun04/nio-reactor: A reference implementation of the Reactor Pattern with Java NIO. - GitHub, accessed April 28, 2025, https://github.com/kasun04/nio-reactor
  51. Simple Explanation for the "Reactor Pattern" with its Applications [closed] - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/5566653/simple-explanation-for-the-reactor-pattern-with-its-applications
  52. Reactor vs. Proactor: Part 1 – The Reactor | Sean Bollin's Software Engineering Blog, accessed April 28, 2025, http://www.sean-bollin.com/2017/05/01/reactor-vs-proactor-part-1-the-reactor/
  53. What is the status of POSIX asynchronous I/O (AIO)? - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/87892/what-is-the-status-of-posix-asynchronous-i-o-aio
  54. How io_uring and eBPF Will Revolutionize Programming in Linux - HackMD, accessed April 28, 2025, https://hackmd.io/@YLowy/rJljf_4F9
  55. how does reactor pattern work in Node.js? - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/56622353/how-does-reactor-pattern-work-in-node-js
  56. The Proactor Design Pattern: Concurrency Without Threads - Asio C++ Library, accessed April 28, 2025, https://think-async.com/Asio/asio-1.18.2/doc/asio/overview/core/async.html
  57. The Proactor Pattern | PPT - SlideShare, accessed April 28, 2025, https://www.slideshare.net/slideshow/the-proactor-pattern/64862
  58. The Proactor Design Pattern: Concurrency Without Threads - Asio C++ Library, accessed April 28, 2025, https://think-async.com/Asio/asio-1.30.2/doc/asio/overview/core/async.html
  59. Asynchronous I/O Library (Asio) - Coconote, accessed April 28, 2025, https://coconote.app/notes/d7a40840-6578-4ce8-90be-0049621c4904
  60. Proactor - Diranieh, accessed April 28, 2025, http://www.diranieh.com/DP/POSA_Proactor.htm
  61. Proactor, accessed April 28, 2025, http://www.laputan.org/pub/sag/proactor.pdf
  62. How io_service matches a completion event with a completion handler - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/45278796/how-io-service-matches-a-completion-event-with-a-completion-handler
  63. What does it mean to be "truly" asynchronous? - Software Engineering Stack Exchange, accessed April 28, 2025, https://softwareengineering.stackexchange.com/questions/454753/what-does-it-mean-to-be-truly-asynchronous
  64. The Reactor and Proactor design patterns - Packt, accessed April 28, 2025, https://www.packtpub.com/en-us/product/asynchronous-programming-with-c-9781835884249/chapter/chapter-9-asynchronous-programming-using-boostasio-13/section/the-reactor-and-proactor-design-patterns-ch13lvl1sec82
  65. The Reactor and Proactor design patterns - Packt, accessed April 28, 2025, https://www.packtpub.com/en-PT/product/asynchronous-programming-with-c-9781835884249/chapter/chapter-9-asynchronous-programming-using-boostasio-13/section/the-reactor-and-proactor-design-patterns-ch13lvl1sec82
  66. Approaches to making io_submit not block - Google Groups, accessed April 28, 2025, https://groups.google.com/g/linux.kernel/c/rFOD6mR2n30/m/13VDXRTmBCgJ
  67. io_uring vs. epoll – Which Is Better in Network Programming? - Alibaba Cloud Community, accessed April 28, 2025, https://www.alibabacloud.com/blog/599544
  68. The Proactor and Reactor Design Patterns - YouTube, accessed April 28, 2025, https://www.youtube.com/watch?v=Vm5l8zH4hOE
  69. fast AIO that supports sockets - C Board, accessed April 28, 2025, https://cboard.cprogramming.com/c-programming/159659-fast-aio-supports-sockets.html
  70. Asynchronous I/O Linux - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/9751345/asynchronous-i-o-linux
  71. Studying and improving POSIX asynchronous IO implemented in GLIBC, accessed April 28, 2025, https://repositories.lib.utexas.edu/items/e5e94af1-9e2a-4fbd-8549-99aa111058eb
  72. Asynchronous I/O and event notification on linux - Davmac.org, accessed April 28, 2025, https://davmac.org/davpage/linux/async-io.html
  73. Asynchronous I/O on linux, accessed April 28, 2025, http://www.cs.fsu.edu/~piyush/teach/4531_06/project/hell.html
  74. Efficient IO with io_uring - kernel.dk, accessed April 28, 2025, https://kernel.dk/io_uring.pdf
  75. GNU C Library Reference Manual, accessed April 28, 2025, https://www.gnu.org/software/libc/manual/html_mono/libc
  76. Yet another comparison between io_uring and epoll on network performance #536 - GitHub, accessed April 28, 2025, Yet another comparison between io_uring and epoll on network performance axboe/liburing#536
  77. Is there really no asynchronous block I/O on Linux? - Stack Overflow, accessed April 28, 2025, https://stackoverflow.com/questions/13407542/is-there-really-no-asynchronous-block-i-o-on-linux
  78. How io_uring and eBPF Will Revolutionize Programming in Linux - ScyllaDB, accessed April 28, 2025, https://www.scylladb.com/2020/05/05/how-io_uring-and-ebpf-will-revolutionize-programming-in-linux/
  79. Performance Characterization of Modern Storage Stacks: POSIX I/O, libaio, SPDK, and io_uring - Atlarge Research, accessed April 28, 2025, https://atlarge-research.com/pdfs/2023-cheops-iostack.pdf
  80. Io_uring is not an event system | Hacker News, accessed April 28, 2025, https://news.ycombinator.com/item?id=27540248
  81. Lord of the io_uring: io_uring tutorial, examples and reference | Hacker News, accessed April 28, 2025, https://news.ycombinator.com/item?id=23132549
@htoooth htoooth changed the title Reactor 与 Proactor 模式深度解析 操作系统:并发io 设计模式 Reactor 与 Proactor 深度解析 Apr 29, 2025
@htoooth htoooth changed the title 操作系统:并发io 设计模式 Reactor 与 Proactor 深度解析 并发系统: Reactor 与 Proactor 深度解析 Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant