Workerman 不允许显式指定 select/epoll,因其事件循环在启动时硬编码环境检测逻辑:Linux 且支持 epoll 则自动启用 epoll,macOS 用 kqueue,Windows 或不支持时回退 select,无配置项、环境变量或参数可覆盖该行为。

Workerman 不能手动切换 select 和 epoll —— 它根据运行环境自动选择,强行干预反而容易出错。
为什么 Workerman 不允许显式指定 select/epoll?
Workerman 的事件循环底层直接调用 PHP 的 stream_select(对应 select/poll)或 Linux 内核的 epoll_wait 系统调用,但封装层不暴露“强制使用某个多路复用器”的开关。它的决策逻辑是硬编码在启动时的环境检测中:
- Linux 系统且内核支持 epoll → 自动启用
epoll(无需额外扩展) - macOS → 自动回退到
kqueue - Windows 或无法检测到 epoll 支持 → 回退到
select
这个过程发生在 Worker::run() 初始化阶段,没有配置项、环境变量或构造参数能覆盖它。
想让 Linux 下的 Workerman 强制用 select 怎么办?
唯一可靠的方式是「欺骗系统检测」:让 Workerman 认为当前不是 Linux 环境。实际操作中,最常用的是修改 PHP_OS_FAMILY 的判定依据——通过临时重定义常量(仅限 CLI 模式):
php -d 'define("PHP_OS_FAMILY", "Windows")' your-worker.php start
但注意这会带来副作用:
-
PHP_OS_FAMILY是只读常量,PHP 8.0+ 会报Warning: Constants may not be redefined,需配合php.ini中error_reporting屏蔽 - 部分 Worker 内部逻辑(如信号处理、文件锁)可能依赖真实 OS 类型,行为异常
- 不是所有版本 Workerman 都响应此 trick;v4.x 后更倾向直接读取
PHP_OS和DIRECTORY_SEPARATOR
更稳妥的做法是:在非 Linux 环境(如 Docker 容器里跑 Windows 子系统 WSL1)下测试 select 行为,而非硬改。
检查当前实际使用的 I/O 多路复用器
别猜,直接看启动日志或代码中打印的检测结果:
- 启动时默认输出类似:
事件循环: epoll或事件循环: select (libevent/libev) - 也可在代码中主动检查:
class_exists('\Workerman\Events\Event')表示用了 libevent 扩展(此时实际是epoll或kqueue封装),否则走纯 PHP 的stream_select - Linux 下用
strace -e trace=epoll_wait,select,poll php your-worker.php start可确认系统调用真实路径
很多问题其实不是“没切成功”,而是误以为自己能切、或者没意识到容器里挂载的内核版本太旧(如某些 Alpine 镜像内核
真正需要关注的不是“切不切”,而是“值不值得切”
epoll 在连接数 > 1000 且活跃度低(比如长连接、心跳保活)时优势明显;select 在连接数 select 调用上,那该优化的是连接管理策略或业务逻辑,而不是换多路复用器。
另外,Workerman v5 开始已默认禁用 libevent 扩展路径,全部走纯 PHP 的 stream_select + 自研事件循环优化,这意味着即使在 Linux 上,也不再严格等同于原生 epoll,而是一种混合模型——这时候纠结“是否 epoll”本身意义已经变小。

















