知识卡片

Proactor:真正异步I/O与Reactor的本质区别及Linux下的现实落差

普通读书笔记卡

内容

Reactor本质上是”非阻塞同步”网络模型——虽然I/O多路复用解决了”阻塞在哪个连接上等待”的问题,但真正的read和send操作依然是由用户进程自己同步执行的,用一句话概括Reactor的运作方式就是”来了事件我(Reactor)通知你(业务代码),你自己去处理”。如果把I/O操作本身也改成异步,让操作系统内核而不是用户进程去真正执行read/send,理论上能进一步提升性能,这就是异步网络模型Proactor(这个名字翻译成”前摄器”不好理解,不如按proactive”主动的”这层含义理解为”主动器”更贴切)。Proactor和Reactor的本质区别可以概括为:Reactor是”来了事件我通知你,你来处理”,Proactor是”来了事件我(操作系统内核)来处理,处理完了我通知你”——这里的”我”从Reactor模式里的框架代码,变成了操作系统内核本身,”事件”依然是新连接、数据可读、数据可写这类I/O事件,”你”是业务代码。具体流程是:Proactor Initiator负责创建Proactor和Handler,并通过Asynchronous Operation Processor把它们注册到内核;Asynchronous Operation Processor负责真正执行I/O操作,操作完成后通知Proactor;Proactor根据不同事件类型回调对应的Handler,Handler这时候拿到的已经是处理完I/O之后的结果,只需要专注业务逻辑,业务处理过程中Handler也可以继续向内核注册新的Handler。理论上Proactor效率应该比Reactor更高,因为真正的异步I/O能利用DMA特性,让I/O操作和CPU计算重叠进行,但真正实现异步I/O需要操作系统底层做大量工作——目前只有Windows通过IOCP真正实现了完整的异步I/O,Linux下的AIO机制并不完善,因此Linux下做高并发网络编程时依然以Reactor模式为主流,即便像Boost.Asio这样号称实现了Proactor模型的库,实际上也是在Windows下用IOCP、在Linux下用Reactor模式(基于epoll)去模拟出一个”看起来异步”的效果,并非Linux下真正意义上的异步I/O。

参考来源

- 位置:《从零开始学架构》第19讲《单服务器高性能模式:Reactor与Proactor》"Proactor"(源文件:_epub-src/OEBPS/text00001.html) - 结论依据:原文说明"Reactor 是非阻塞同步网络模型……如果把 I/O 操作改为异步就能够进一步提升性能,这就是异步网络模型 Proactor……Reactor 可以理解为'来了事件我通知你,你来处理',而 Proactor 可以理解为'来了事件我来处理,处理完了我通知你'",并说明"目前 Windows 下通过 IOCP 实现了真正的异步 I/O,而在 Linux 系统下的 AIO 并不完善……即使 Boost.Asio 号称实现了 Proactor 模型,其实它在 Windows 下采用 IOCP,而在 Linux 下是用 Reactor 模式(采用 epoll)模拟出来的异步模型",直接支撑本卡片结论。 - 原始内容:Reactor 可以理解为"来了事件我通知你,你来处理",而 Proactor 可以理解为"来了事件我来处理,处理完了我通知你"……目前 Windows 下通过 IOCP 实现了真正的异步 I/O,而在 Linux 系统下的 AIO 并不完善,因此在 Linux 下实现高并发网络编程时都是以 Reactor 模式为主。