Workerman 用 Swow 驱动需满足:PHP ≥ 8.0、已安装启用 swow 扩展、Workerman ≥ 4.1.0、前台启动(禁用 daemon)、设置 Worker::$eventLoopClass = \Swow\EventLoop::class 并禁用默认定时器。

Workerman 用 Swow 驱动要满足哪些前提条件
Workerman 本身不原生支持 Swow,必须通过 swow 扩展 + 修改启动方式绕过默认事件循环,否则直接报错或降级回 stream_select。Swow 不是 Workerman 的插件,而是替代其底层 I/O 调度的协程运行时。
关键检查点:
- PHP 版本 ≥ 8.0(Swow 仅支持 PHP 8+)
-
swow扩展已安装且启用(php -m | grep swow要有输出) - Workerman 版本 ≥ 4.1.0(低版本无
Worker::$eventLoopClass控制入口) - 不能使用
php start.php start -d直接启 daemon 模式——Swow 不支持 fork 后的协程上下文继承,必须用php start.php start前台运行
如何让 Workerman 加载 Swow 事件循环
核心是替换 Workerman 默认的 EventLoop 实现。Swow 提供了兼容接口,但需手动注入,不能靠配置文件自动加载。
实操步骤:
- 在 Workerman 启动文件(如
start.php)顶部引入 Swow:require_once 'vendor/autoload.php';(确保已composer require swow/swow) - 在
use Workerman\Worker;后、Worker::runAll()前设置:Worker::$eventLoopClass = \Swow\EventLoop::class; - 禁用 Workerman 自带的定时器驱动(Swow 自带更高效的
Timer):设置Worker::$timerInterval = 0; - Swow 不支持
stream_socket_server的阻塞模式,所有监听必须用SOCK_STREAM | SOCK_NONBLOCK,Workerman 会自动适配,但自定义 socket 时要注意
Swow 驱动下协程化写法和常见翻车点
启用 Swow 后,Workerman 的每个 worker 进程变成一个协程调度器,但「协程安全」不等于「自动协程化」——原有同步阻塞调用(如 file_get_contents、curl_exec)依然会卡住整个协程调度器。
必须改写为 Swow 兼容的异步调用:
- HTTP 请求别用
curl_exec,改用Swow\Http\Client或Swow\Coroutine\Http\Client - Redis 别用
phpredis,要用Swow\Redis或co\Redis(Swow 封装版) - MySQL 别用
PDO或mysqli,必须用Swow\MySQL或co\MySQL - 日志写入不能直接
file_put_contents,得用Swow\IO\Stdio或异步写入队列,否则高并发下 IO 成瓶颈
典型错误现象:PHP Fatal error: Uncaught Swow\Exception: Cannot use blocking I/O in coroutine context —— 就是上面某条没改干净。
性能差异和实际部署注意事项
Swow 在单核吞吐上比 Workerman 默认 event-loop 高 2–5 倍(取决于 IO 密集程度),但内存占用略高(每个协程约 256KB 栈空间),且不支持多进程热重启(reload 会失败)。
生产环境要特别注意:
- 不能用
kill -USR1触发 reload,只能kill -TERM全量重启,需配合进程管理器(如 supervisor)做平滑上线 - Docker 容器内运行需加
--cap-add=SYS_PTRACE(Swow 调试依赖 ptrace) - Swow 的
gethostbyname是同步阻塞的,DNS 查询务必用Swow\Coroutine\DNS替代 - 调试时
debug_backtrace()看不到完整协程栈,得用Swow\Coroutine::getCurrent()->getTrace()
Swow 不是“开箱即用的加速器”,它是把 Workerman 推进协程深水区的一把刀——用对了切得快,用错了容易切到手,尤其是那些藏在第三方 SDK 里的同步调用,最容易漏掉。











