Swoole协程需用co::sleep等协程API、协程版MySQL/Redis/HTTP客户端,禁用同步阻塞函数;须在Swoole环境(Co\run或HttpServer)中启用enable_coroutine运行,否则静默失败。

PHP 里用 Swoole 协程做异步任务,不是加个 go 就完事
协程不是“多线程”,也不是“后台进程”。它本质是单线程内的非阻塞调度——go 启动的函数会立刻返回,但只有遇到真正可挂起的操作(比如 co::sleep、MySQL::query、Http\Client->get)才会让出控制权。如果你在协程里写了个死循环或调了 sleep(1)(非协程版),整个服务就卡住。
-
sleep()是同步阻塞,必须换成co::sleep() - 普通 MySQL 扩展不支持协程,得用
Swoole\Coroutine\MySQL - 第三方 SDK(如 Redis、Elasticsearch 客户端)要确认是否内置协程适配,否则得自己封装或换库
- 协程上下文不共享全局变量和静态属性,
$GLOBALS、static $x在不同go中互不影响
启动协程前,先确认 Swoole 环境和运行模式
你写的协程代码,只在 Swoole 的协程模式下生效。CLI 下直接 php script.php 运行,go 会静默失败(不报错,也不执行);必须用 swoole_server 或 Co\run 包裹。
- 开发调试时,用
Co\run(fn() => { go(fn() => { /* ... */ }); });最简单 - Web 场景下,必须基于
Swoole\Http\Server或Swoole\WebSocket\Server,且设置enable_coroutine => true(默认开启) - 检查是否启用协程:运行
php --ri swoole,看输出中是否有coroutine => enabled - 别在 Apache / Nginx + PHP-FPM 下试图跑协程——它们根本不支持
数据库、HTTP、文件 IO 这些操作,必须用协程版 API
协程的“异步感”全靠底层 IO 调用能主动让出 CPU。普通函数(如 file_get_contents、curl_exec)仍是阻塞的,放进 go 也白搭。
- HTTP 请求:用
Swoole\Coroutine\Http\Client,不用 cURL 或 Guzzle(除非它明确支持协程驱动) - MySQL 查询:用
$mysql = new Swoole\Coroutine\MySQL(); $mysql->connect(...); $mysql->query(...) - Redis:优先选
Swoole\Coroutine\Redis,不是Redis扩展原生类 - 读文件:用
co::readFile,别用file_get_contents;写文件同理用co::writeFile - 注意连接数限制:
Swoole\Coroutine\MySQL默认复用连接,但高并发下仍需合理配置max_coroutine和连接池
协程间通信和错误处理,比想象中容易漏掉
协程崩溃不会终止主进程,但错误会被吞掉——没加 try/catch,或者没监听 Swoole\Event::wait() 异常,任务就悄无声息地失败了。
立即学习“PHP免费学习笔记(深入)”;
- 每个
go内部建议包一层try/catch,捕获Throwable - 需要结果传递?用
Swoole\Coroutine\Channel,别依赖 return 值(协程函数不等执行完就返回了) - 想等所有协程结束?用
Co\WaitGroup,不是array_map+go - 日志记录要注意:协程 ID(
Co::getcid())应打到每条日志里,否则排查时分不清谁干的
协程的“轻量”是假象——写错一个挂起点,或混用同步/协程 API,整条请求链路就退化成同步阻塞。最麻烦的不是不会写,而是以为写对了,其实没生效。



















