① epoll 内核数据结构动态演示
点击「epoll_ctl ADD」注册一个 fd 进红黑树;点击「触发数据」模拟某个 fd 收到数据 → 内核回调把它放进就绪链表;点击「epoll_wait」拿走就绪 fd。
🌲 红黑树(监听集 - 所有被 epoll_ctl ADD 的 fd)
📥 就绪链表(已就绪的 fd, 等待 epoll_wait 取走)
→ 操作上方按钮观察内核行为
② LT vs ET 模式触发对比
同样的"socket 收到 10 字节"事件,对 LT 和 ET 的差异。"读 4 字节"按钮模拟你只读了一部分——观察下次 epoll_wait 是否还会通知。
💧 LT 模式(水平触发,默认)
缓冲区数据 (字节):
epoll_wait 通知次数: 0 · 累计读取: 0 字节
⚡ ET 模式(边沿触发)
缓冲区数据 (字节):
epoll_wait 通知次数: 0 · 累计读取: 0 字节
🚨
关键观察:当你只读 4 字节后再调 epoll_wait——
- LT:会继续通知"你还有数据没读完!" → 安全 ✅
- ET:不通知!状态没变化 → 你以为读完了,但还有 6 字节藏在缓冲区 ⚠️
→ 这就是为什么
ET 必须循环读到 EAGAIN,否则丢数据。
③ select / poll / epoll 性能定量对比
基于内核数据结构推导的开销公式(教学示意值)。修改 fd 数和就绪率,看三者的差距如何放大。
💡 关键洞察:当监听 fd 多但就绪少时(最常见的高并发场景),epoll 比 select/poll 快 几十到几百倍。
但如果 所有 fd 都同时就绪(边界场景),三者性能会接近——所以"epoll 不一定永远最快",要看场景。