PHP协程异步编程必须依赖Swoole运行时环境:需在脚本开头调用Swoole\Runtime::enableCoroutine(),替换所有阻塞I/O为协程安全函数(如co::httpGet、co::mysql),并显式启动事件循环(如Swoole\Event::wait或Swoole\Coroutine\run),否则仍为同步阻塞。

PHP 协程异步编程不是“加个 go() 就能跑”,它依赖 Swoole 运行时环境和协程安全的 I/O 函数,否则会退化成同步阻塞——哪怕你写了 10 个 go(),只要里面调用 file_get_contents 或 PDO::query,整个协程就卡住。
必须启用 Swoole 协程运行时
Swoole 4.5+ 默认不自动启用协程 Hook,原生 PHP 函数仍走同步路径。不显式开启,co::sleep()、co::httpGet() 都会报错或无效。
-
Swoole\Runtime::enableCoroutine()必须在脚本最开头调用(早于任何其他逻辑) - 若使用
Swoole\Http\Server等 Server 类,可在构造后调用$server->set(['hook_flags' => SWOOLE_HOOK_ALL])替代 - 仅在 CLI 模式下有效;FPM、Apache mod_php 下完全不生效
- 启用后,部分系统函数(如
sleep、file_get_contents、curl_exec)会被自动协程化,但数据库和 HTTP 客户端仍需手动换库
必须替换所有阻塞 I/O 调用
协程调度器只接管 Swoole 封装的 I/O 函数。混用原生同步函数会导致当前协程挂起,阻塞同一线程内所有其他协程。
- HTTP 请求:弃用
file_get_contents、cURL,改用Swoole\Coroutine\Http\Client或co::httpGet() - MySQL 查询:弃用
PDO和mysqli,改用Swoole\Coroutine\Mysql(Swoole 4.8+ 推荐co::mysql()) - Redis:弃用
phpredis,改用Swoole\Coroutine\Redis或co::redis() - 文件读写:Swoole 4.7+ 支持
co::readFile()、co::writeFile();旧版本需自己封装或跳过
协程启动与事件循环必须显式管理
go() 只是注册协程任务,不启动调度;没有事件循环,协程根本不会执行。
- 在普通 CLI 脚本中,必须在最后调用
Swoole\Event::wait()或Swoole\Coroutine\run()(Swoole 4.8+) - 在
Swoole\Http\Server中,事件循环由 Server 内部启动,无需手动调用wait() - 错误写法:
go(function() { co::sleep(1); }); echo "done";—— 输出done后脚本直接退出,协程没机会执行 - 正确写法:
go(function() { co::sleep(1); echo "after sleep"; }); Swoole\Event::wait();
协程不是多线程,共享变量需格外小心
协程间共享全局变量、静态属性或 use 的外部变量是安全的(单线程),但容易因执行顺序不可控导致逻辑错乱。
- 避免在多个协程中同时修改同一个数组或对象属性,除非你明确知道执行时机
- 不要依赖
microtime(true)或rand()的“顺序性”——协程切换快于毫秒级精度 - 调试时用
co::getuid()区分协程上下文,比getmypid()更可靠 - 日志写入建议用
co::writeFile()或推送到 Redis 队列,别直接error_log()(可能被并发覆盖)
最容易被忽略的是:协程异步能力只存在于 Swoole Server 生命周期内。一旦你用 php script.php 运行一个普通脚本,哪怕装了 Swoole、写了 go()、启用了 enableCoroutine(),只要没进 Event::wait() 或没跑在 Server 实例里,它就是个同步脚本——这点和 Node.js 或 Python asyncio 有本质区别。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











