PHP 8.6 的 Io\Poll:用 epoll/kqueue 替掉手写的 stream_select()
PHP 8.6 新增 Io\Poll 命名空间,提供统一的轮询(readiness multiplexing)接口。后端按平台选择:Linux 用 epoll,BSD/macOS 用 kqueue,Solaris 用 event ports,Windows 用 WSAPoll。对应的 RFC 是 Polling API,已在 PHP 8.6 被接受并实现。
为什么替掉 stream_select()
stream_select() 在用户态被到处手写,问题集中在四点:
- fd 数量受
FD_SETSIZE限制,通常只有 1024; - 每次调用都要重新构造
fd_set; - 返回后需要 O(n) 扫描才知道哪些 fd 就绪;
- 没有跨平台的事件通知模型。
Io\Poll 把这几件事收进引擎:事件循环不再需要依赖 stream_select()。
接口组成
Io\Poll 下的核心类型是 Context、Event、StreamPollHandle,配合非阻塞 socket 使用。
同一版本还新增了 Time\Duration:最终 readonly 类,纳秒精度。它作为超时/时长的共享类型,供新的轮询 API 使用。
谁需要关心
主要动机来自 PHP 内部——信号处理与 FPM 的工作;次要受众才是用户态的事件循环与异步运行时,比如 ReactPHP、Revolt、AMPHP 这一类。
背景是引擎层一直没有并发调度:Fibers(8.1)只提供协作式切换的底层原语,事件循环留给用户态,于是各家框架各搞一套互不兼容的实现。Polling API 被看作未来引擎级调度器(async scheduler ABI,目标 8.7+)的 I/O 基础。
现在的取舍
- 跨平台的事件通知由引擎统一提供,取代用户在
stream_select()之上自行分平台适配。 - 8.6 落地的是轮询这一层;引擎级调度器仍标注为 8.7+ 的目标,尚未到来。
Io\Poll与Time\Duration都是 8.6 的新 API,兼容性上只对 8.6+ 有效。