协程 context 是每个协程独占的哈希表,用于隔离本协程数据;全局变量如 $_server、static、$globals 在协程间共享且不安全,易导致并发污染。

协程 Context 是隔离的,全局变量是共享的
协程 Context 本质是每个协程独占的一块哈希表,Co::getContext() 返回的对象只对该协程可见;而 $_SERVER、static $counter、$GLOBALS 这类全局状态,所有协程运行在同一个进程里,会互相覆盖。
常见错误现象:
- 用
static $req_id = 0; $req_id++生成请求序号,结果并发时序号乱跳、重复 - 在
onRequest回调里往$_SESSION写数据,下一个协程读出来是上一个请求的残留值 - 第三方 SDK 内部用
global $config存配置,协程 A 改了,协程 B 立刻受影响
Context 的 set/get 不触发协程切换,但全局变量访问永远不安全
$ctx->set('user_id', 123) 和 $ctx->get('user_id') 是纯内存操作,不涉及 I/O,也不依赖 Swoole Hook;而任何对全局变量的读写,哪怕只是 isset($GLOBALS['trace']),都可能在协程让出后被其他协程篡改。
使用场景判断要点:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 跨函数传递请求 ID、用户 Token、日志 trace_id —— 必须用
Co::getContext() - 需要在
Co::defer()里清理资源(如关闭临时文件句柄)—— 只能靠 Context 拿到当时存的句柄 - 类内部缓存当前请求的数据库连接实例 —— 不能用
static $conn,得存在 Context 里再传给方法参数
Context 不等于“自动透传”,子协程默认拿不到父协程数据
Co::getContext() 默认返回当前协程的上下文,不是继承关系。你用 go(function () { ... }) 启动新协程,它拿到的是空 Context,除非显式传参或用 Co::getPcid() 主动获取父协程 ID 再查。
容易踩的坑:
- 在父协程设了
$ctx->set('auth', $token),子协程直接$ctx->get('auth')得到null - 误以为 Context 像 PHP 的
context流上下文一样自动传播,其实完全不传播 - 用
Easyswoole\Component\Context\ContextManager时没传$cid,结果存到了当前协程,取的时候却查了别的协程 ID
Context 无法替代 Channel 或 Atomic,别用它做跨协程通信
Context 只解决“本协程内数据隔离”,不是线程/协程间同步机制。如果你需要多个协程共同更新一个计数器、或者等待某个异步任务完成,Co::getContext() 完全无用。
正确做法:
- 计数、开关状态 → 用
Swoole\Atomic或Swoole\Table - 生产者-消费者模型 → 用
Swoole\Coroutine\Channel - 临界区保护 → 用
Swoole\Coroutine\Lock(注意:Lock 在协程间不可重入) - 想让子协程“知道”父协程的某个值 → 显式传参,或用
Co::getContext(Co::getPcid())查父协程 Context
set/get,而是误把它当成“协程版 global”或“协程版 $_SERVER”。










