首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >不用等升级 PHP8.6!原生 Poll API 现在 PHP8.1 就能体验

不用等升级 PHP8.6!原生 Poll API 现在 PHP8.1 就能体验

作者头像
Tinywan
发布于 2026-09-15 14:34:52
发布于 2026-09-15 14:34:52
2170
举报
文章被收录于专栏:开源技术小栈开源技术小栈

原生 Poll API 现在 PHP8.1 就能体验

PHP 8.6 的 Io\Poll API 让 PHP 引擎第一次原生支持 epoll/kqueue,无需任何 C 扩展。本文介绍这个新 API、基于它(及 Symfony polyfill)编写的 Workerman 事件循环驱动,以及安装使用方法与性能实测。

01  PHP 8.6 的新 I/O API:Io\Poll

1.1 它解决什么问题

长期以来,PHP 想做高性能网络服务只有两条路:

  • stream_select():内置但能力有限——fd 上限约 1024(FD_SETSIZE),每轮全量扫描,O(n) 复杂度;
  • 装 C 扩展:Swoole、Ev、Event 等,性能好但要编译安装、有运行时侵入。

PHP 8.6 合入了 Poll API RFC,把 epoll(Linux)、kqueue(macOS/BSD)、WSAPoll(Windows)直接做进了引擎:

特性

说明

零扩展依赖

引擎内置,composer 生态直接可用

标准多路复用

就绪事件通知,O(1) 获取就绪 fd

无 fd 上限

摆脱 FD_SETSIZE 1024 限制

与 Fiber 配合

未来异步框架的原生底座

1.2 API 长什么样

核心概念有四个:

概念

作用

Io\Poll\Context

轮询上下文,注册/监视多个句柄,支持 Read、Write、Error、Hang-up 事件

Io\Poll\Event

事件类型枚举,如 Event::Read

Watcher

wait() 返回的就绪对象,可携带自定义应用数据,可动态修改或移除

StreamPollHandle

把 PHP 原生流资源包装成 Poll 可识别的句柄

看一个官方风格的 TCP 服务器示例:

use Io\Poll\Context;

use Io\Poll\Event;

use StreamPollHandle;

$server = stream_socket_server('tcp://127.0.0.1:8080');

$poll = new Context();

poll->add(new StreamPollHandle(

// 阻塞等待事件(超时 30 秒),只返回就绪的 watcher

foreach (poll->wait(timeoutSeconds: 30) as 

if ($watcher->hasTriggered(Event::Read)) {

connection = stream_socket_accept(watcher->getHandle()->getStream());

        // 处理新连接...

    }

}

对比 stream_select(),最大的区别是状态化的:fd 注册一次,之后每轮 wait() 只返回就绪者;而 stream_select 每轮都要把所有 fd 集合重新传进去、全量比对,还要自己维护几组平行数组。

1.3 Symfony polyfill:PHP 8.1 就能用

Symfony 团队在 1.41.0 版本同步发布了 symfony/polyfill-io-poll,把这个 API 反向移植到 PHP 8.1+。公告里一语道破了它的价值:

◆ Symfony 官方公告

以往使用 stream_select() 时,异步框架和应用必须管理复杂的平行数组,并处理各种平台限制。Io\Poll 彻底解决了这一痛点,让开发者能够在旧版 PHP 中提前写出更现代、更易维护的异步网络代码。

运行机制:

  • PHP 8.1 ~ 8.5:polyfill 接管,提供完全一致的 API(内部基于 stream_select 的可移植实现);
  • PHP 8.6+:polyfill 自动让位给引擎原生实现,并按平台智能选择 epoll / kqueue / WSAPoll 后端。

两个注意点(同样来自公告与实测):

  1. polyfill 使用可移植后端,只支持水平触发(level-triggered),不支持边缘触发;
  2. 已发布的 polyfill 1.41 与原生 8.6 的 wait() 参数风格略有差异(整数秒 vs Time\Duration),上游正在统一,跨版本代码需要稍作兼容(本文的驱动已处理)。

这意味着:同一份代码,升级 PHP 版本就自动获得 epoll 级性能,零改动。这就是我为 Workerman 写这个驱动的原因。

02  Workerman 的事件循环是怎么插拔的

Workerman 5.x 把所有 I/O 多路复用抽象在 Workerman\Events\EventInterface 接口里,内置了 Select、Ev、Event、Swoole、Swow 等驱动。切换驱动只需一行:

Worker::$eventLoopClass = \Workerman\Events\Select::class;

接口方法一览(就是驱动要实现的全部):

方法

作用

onReadable / offReadable

注册/取消流可读回调

onWritable / offWritable

注册/取消流可写回调

delay / offDelay

一次性定时器

repeat / offRepeat

重复定时器

onSignal / offSignal

信号处理

run / stop

启动/停止事件循环

03  安装与使用

3.1 安装

composer require tinywan/workerman-event-poll

要求:

环境

依赖

PHP 8.6+

无(引擎内置 Io\Poll)

PHP 8.1 ~ 8.5

symfony/polyfill-io-poll(自动安装)

POSIX 系统

ext-pcntl、ext-posix(Workerman 本身的要求)

3.2 使用

<?php

require __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;

use Workerman\Events\Poll;

Worker::$eventLoopClass = Poll::class;

$worker = new Worker('http://0.0.0.0:8080');

worker->onMessage = function (

$connection->send('hello');

};

Worker::runAll();

启动后执行 php start.php status,event-loop 列显示 poll 即生效:

代码语言:javascript
复制
php server.php start Workerman[server.php] start in DEBUG mode --------------------------------------------- WORKERMAN --------------------------------------------- Workerman/5.2.2         PHP/8.4.15 (JIT off)          Linux/6.18.33.2-microsoft-standard-WSL2 ---------------------------------------------- WORKERS ---------------------------------------------- event-loop  proto       user        worker       listen                 count       state poll        tcp         root        poll-tcp     tcp://0.0.0.0:2345     1            [OK] poll        tcp         root        poll-http    http://0.0.0.0:8401    1            [OK] ----------------------------------------------------------------------------------------------------- Press Ctrl+C to stop. Start success.

TCP、WebSocket、定时器、信号全部照常工作,业务代码不需要任何改动——这就是"drop-in replacement"的意义。

3.3 自动兑现验证

同一份代码在两个 PHP 版本下的实际运行效果:

运行时

底层实现

结果

PHP 8.4 + polyfill

stream_select(polyfill 内部)

TCP/HTTP/定时器全部通过

PHP 8.6.0beta1

引擎原生 epoll

同上,零改动

04  性能实测(wrk 压测摘要)

单进程、wrk -t2 -c200 -d20s、最小 HTTP 响应:

配置

RPS

说明

PHP 8.6 + Poll(原生 epoll)

~51,500

全场第一

Swoole 原生(关协程,参照)

~42,000

C 扩展引擎

PHP 8.4 + Poll(polyfill)

~25,750

比内置 Select 快约 15%

PHP 8.4 + Select(内置)

~22,450

Workerman 默认回退

4 worker 多进程:8.6 原生 Poll ~119k,仍是第一;polyfill 阶段(~71k)则不及 Select(~99k)——polyfill 是纯 PHP 实现,它的价值在 API 兼容与升级路径,8.1~8.5 追求多进程极限吞吐建议继续用 Select/Ev/Event。完整数据与复现脚本见仓库 BENCHMARK.md 和 examples/bench.sh。

05  总结

问题

答案

这个驱动现在有什么用?

PHP 8.1~8.5 单进程场景比默认 Select 快 15%,且无 fd 上限焦虑

真正的价值?

零改动升级路径:升 PHP 8.6 自动切换引擎级 epoll,吞吐翻倍

为什么不等 8.6 再写?

驱动 API 现在就固定下来,8.6 到来时业务代码一行不用改

项目地址:github.com/Tinywan/workerman-event-Poll,MIT 协议,欢迎 Star、Issue 和 PR。

相关链接

▸ PHP RFC: Poll API wiki.php.net/rfc/poll_api

▸ Symfony Polyfill 1.41.0 发布公告 symfony.com/blog/symfony-polyfill-1-41-0-released-io-poll-now-available

▸ symfony/polyfill 仓库 github.com/symfony/polyfill

▸ 本项目仓库 github.com/Tinywan/workerman-event-Poll

— END —

觉得有用的话,欢迎点赞、在看、转发, 你的支持是我继续折腾 PHP 新特性的动力。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-08-17,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 原生 Poll API 现在 PHP8.1 就能体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档