Redis、Nginx、Netty 为什么快?因为它们底层都用 epoll。select、poll、epoll 到底什么区别?Java NIO 怎么映射到 Linux IO 模型?Reactor 模式怎么实现?一篇讲透。
一、五种 IO 模型
1.1 全景图
应用程序调用 recvfrom() 读数据的过程:
模型1:阻塞 IO(Blocking IO)
用户线程:调用 recvfrom() → 阻塞 → 阻塞 → 阻塞 → 数据返回
特点:整个等待 + 复制过程都阻塞
模型2:非阻塞 IO(Non-blocking IO)
用户线程:调用 recvfrom() → 立即返回 EWOULDBLOCK
再次调用 → EWOULDBLOCK → ... → 数据就绪 → 复制 → 返回
特点:等待不阻塞但需要轮询(CPU 浪费)
模型3:IO 多路复用(IO Multiplexing)
用户线程:调用 select/poll/epoll → 阻塞等待(可同时监控多个 FD)
数据就绪 → 返回 → 调用 recvfrom() 复制数据
特点:一个线程监控多个连接
模型4:信号驱动 IO(Signal-driven IO)
用户线程:注册 SIGIO 信号 → 做其他事 → 数据就绪 → 收到信号
→ 调用 recvfrom() 复制数据
特点:等待不阻塞,复制时阻塞
模型5:异步 IO(Asynchronous IO)
用户线程:调用 aio_read() → 立即返回 → 做其他事
→ 数据复制完成 → 回调通知
特点:全过程不阻塞(等待 + 复制都不阻塞)
Linux: io_uring(5.1+)/ AIO
Windows: IOCP
┌─────────────────────────────────────────────────────┐
│ │
│ 阻塞 等待数据 复制数据 │
│ IO ████████ ████ │
│ │
│ 非阻塞 轮询(不阻塞) ████ │
│ IO poll poll poll ████ │
│ │
│ IO多路复用 select阻塞 ████ │
│ (epoll) (可监控多FD) ████ │
│ │
│ 信号驱动 信号通知 ████ │
│ IO (不阻塞) ████ │
│ │
│ 异步IO 不阻塞 不阻塞 │
│ (AIO) (回调通知) (内核完成) │
│ │
└─────────────────────────────────────────────────────┘
2026/7/3大约 8 分钟