协程在Webman中需手动启用并验证生效,否则file_get_contents、PDO::query等同步调用仍会阻塞Worker;必须显式配置eventLoop为Workerman\Events\Swoole::class,替换所有I/O为对应协程客户端,并确保驱动与客户端配套使用。

协程在Webman里不是开箱即用的,不手动配置就等于没开——file_get_contents、PDO::query、curl_exec 这些调用依然会卡死整个 Worker。
确认协程驱动已启用且生效
Webman 默认不启用协程,哪怕你装了 swoole 扩展,也得显式指定驱动并验证是否真跑起来了。
- 执行
php -m | grep swoole(或swow)确认扩展已加载 - 在
config/process.php中为对应进程设置'eventLoop' => Workerman\Events\Swoole::class(别写字符串,必须是类名) - 重启服务后,在
onWorkerStart里打印Workerman\Events\EventInterface::class,输出必须是Workerman\Events\Swoole,而不是Select或Event - 如果用
Fiber驱动(即Revolt),注意它不支持毫秒级定时器,也不适合高并发 IO 场景,仅作兼容备用
替换所有同步 I/O 为协程客户端
协程不会自动“翻译”你的旧代码。只要还用原生同步函数,协程就形同虚设。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- HTTP 请求:必须用
Swoole\Coroutine\Http\Client,禁用guzzlehttp/guzzle和file_get_contents - MySQL 查询:改用
Swoole\Coroutine\Mysql,不是PDO+workerman/webman-database的同步模式(后者在未启用协程驱动时会退化) - Redis 操作:换成
Swoole\Coroutine\Redis,phpredis扩展的connect、get全部阻塞 - 文件读写:用
Swoole\Coroutine\System::readFile/writeFile,file_get_contents和fopen仍会挂起当前协程 - AI 接口流式响应(如 OpenAI):优先选
webman-php/openai,它封装了 SSE 解析;原生HttpClient需手动按data:行切分
并发发起多个 IO 任务时别串行写
协程的价值体现在“同时等”,而不是“一个接一个等”。常见错误是把 10 个请求写成 for 循环调用,实际仍是串行。
- 正确做法:用
go(function () { ... })启 10 个子协程,每个持独立HttpClient实例 - 协调完成时机用
Swoole\Coroutine\WaitGroup,不要靠 sleep 或轮询 - 数据库批量 COUNT 统计:5 个表同时
query,总耗时 ≈ 最慢那个,不是 5 倍叠加 - 注意连接池:
Swoole\Coroutine\Mysql本身不带池,高频场景需自己封装或引入webman/mysql并配max_active、max_idle_time
别在协程里碰全局变量和连接对象属性
协程间变量隔离是自动的,但开发者容易误以为“赋个值就能跨协程/回调访问”,结果查不到、存丢了。
-
$_SESSION、$_COOKIE在协程内安全,但自定义静态变量(如self::$cache)会被所有协程共享,必须加锁或换用协程上下文容器 -
$connection->playerId = 123在 WebSocketonMessage里无效——$connection对象每次回调都是新实例,属性不保留 - 玩家状态必须存外部:用
$connection->getFd()当 key,写入Swoole\Table或 Redis Hash,且务必在onClose清理 - 日志记录要带
Co::getcid()和 TraceID,否则排查时无法还原单次请求链路
最容易被忽略的是:协程驱动和协程客户端必须配套。只开了 Swoole 驱动,但数据库还在用 PDO,那 DB 层就是瓶颈;HTTP 用了协程 client,但上传文件仍走 move_uploaded_file,磁盘 IO 又卡住整个 Worker。IO 密集型任务的效率提升,取决于最慢的那个环节是否协程化。

















