PHP协程依赖Swoole扩展,需用go()启动;co::sleep()让出控制权,usleep()则阻塞进程;禁用同步函数,推荐协程客户端;协程间变量隔离,需用Co::getContext()传递数据。

PHP 本身没有原生协程语法(async/await),所谓“PHP 协程”实际依赖 Swoole 扩展提供的用户态协程调度器;不装 Swoole 或没启用 Coroutine,go()、co::sleep() 这些全会报错或静默失效。
协程启动必须用 go() 或 Swoole\Coroutine::create()
协程不是自动开启的——哪怕你写了 co::sleep(1),如果不在协程上下文中执行,它就等同于阻塞的 sleep(1),直接卡主线程。
-
go(function () { co::sleep(1); echo "done"; });是正确入口,Swoole 自动创建并调度协程 - 在
onRequest、onReceive等 Swoole 回调里,当前上下文默认已是协程环境,可直接调用co::sleep()、Co\MySQL->query()等 - 普通 CLI 脚本中漏掉
go(),代码看似跑通,但所有 I/O 操作退化为同步阻塞,完全失去协程意义
co::sleep() 和 usleep() 行为完全不同
co::sleep(1) 让当前协程让出控制权,调度器可切走执行其他协程;而 usleep(1000000) 是系统级阻塞,整个进程卡死,所有协程停摆。
- 协程内禁止使用
sleep()、usleep()、file_get_contents()(未启用协程 Hook 时)等同步函数 - 启用
Swoole\Runtime::enableCoroutine()后,部分 PHP 标准库函数(如curl_exec、stream_socket_client)会被自动协程化,但仍有例外,比如fopen("http://...")不支持 - 推荐显式使用协程客户端:用
Co\Redis替代Redis,用Co\MySQL替代mysqli,避免隐式阻塞
协程变量隔离靠 Co::getContext(),不是全局变量
每个协程有独立的上下文栈,$_SESSION、global $x、静态属性在协程间不共享也不安全——多个协程并发修改同一全局变量会冲突。
立即学习“PHP免费学习笔记(深入)”;
- 需跨协程传递数据?用
Co::getContext()获取当前协程上下文数组,存取自定义键值,例如:Co::getContext()['trace_id'] = $id; - 不要在协程里改
$_SERVER或$GLOBALS,下个请求/协程看到的可能是脏数据 - 数据库连接、Redis 实例等资源对象不能复用到不同协程,
Co\MySQL等协程客户端内部已做连接池管理,直接 new 即可
协程不是线程,没有真正的并行;它的高效建立在“大部分时间在等 I/O”的前提上。一旦协程里混入密集 CPU 计算(比如大循环、图像处理),整个事件循环会被拖慢,其他协程饿死——这种场景得交给 Swow\Process 或投递到 TaskWorker 处理。



















