极高 进阶
IO多路复用#
一句话答案#
一个线程同时监听多个 IO 事件(fd),哪个就绪处理哪个,避免每连接一线程,实现有 select/poll/epoll。
核心要点
核心思想: 不阻塞在单个 IO 上,而是同时监听多个 fd,哪个就绪处理哪个
三种实现: select(数组1024限制) → poll(链表无限制) → epoll(红黑树+就绪链表,最高效)
面试回答(2分钟版)
IO多路复用的核心思想是用一个线程同时监听多个文件描述符的IO事件,哪个就绪就处理哪个,避免了传统BIO模型中每个连接都需要一个线程阻塞等待的问题。Linux下有三种实现:select最早出现,用fd_set位图存储fd,有FD_SETSIZE默认1024的数量限制,每次调用需要把fd集合拷贝到内核并O(n)遍历检查就绪状态;poll用链表替代位图去掉了数量限制,但遍历效率同样是O(n);epoll是最优方案,用红黑树管理fd注册一次即可,事件就绪通过回调加入就绪链表,epoll_wait直接返回就绪fd列表,效率O(1)。需要特别强调的是IO多路复用属于同步IO模型,因为数据从内核拷贝到用户空间这一步仍然是同步阻塞的,真正的异步IO是Linux的AIO或Windows的IOCP,内核完成所有操作后通知用户进程。Java NIO的Selector底层在Linux上就是epoll实现,Redis和Nginx的高并发能力都依赖IO多路复用。
追问与易错
追问方向:
- “IO 多路复用是同步还是异步?”→ 是同步 IO,因为数据从内核拷贝到用户空间仍需进程自己完成(阻塞等待);真正的异步 IO 是 AIO/IOCP,内核全程搞定后通知进程
- “select/poll/epoll 区别?”→ select 有 1024 fd 限制且 O(n) 遍历,poll 无限制但仍 O(n),epoll 红黑树 + 回调就绪链表 O(1) 最高效
- “Java NIO 用的是哪个?”→ Java NIO 的 Selector 在 Linux 上底层用 epoll,macOS 上用 kqueue,Windows 上用 select/poll(JDK 实现自动适配平台)
易错点:
- ❌ IO 多路复用是异步 IO——不是,是同步非阻塞
- ❌ 只能用于网络——也可用于文件 IO