知识卡片
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。