1. Swoole 的 go() 做了什么?
在 PHP + Swoole 中:
go(function () {
co::sleep(1);
echo "done\n";
});
go() 会启动一个 用户态协程 (Coroutine),基于 协程调度器(Swoole runtime)来运行。
- 它和 Go 的 goroutine 类似,但不是系统线程,是 用户态的协程切换(有点像 PHP8 Fiber 的封装+调度器实现)。
- 由 Swoole 内置的调度器负责调度、挂起、继续执行。
2. Swoole 协程的管理方式
与 Golang Context 不同,Swoole 的协程取消/生命周期控制有以下特点:
- 协程 ID:每个
go() 启动的协程在 Swoole 内部有一个 ID(Co::getCid() 可以获取)。
- 退出:协程必须在函数体内自行 return 才能优雅结束,外部不能直接强制 kill(除非调用
Co::cancel(),但这是后来加的,并且可能导致资源状态复杂)。
- 超时控制:通常要配合
chan、defer 或 Swoole 的 Coroutine\WaitGroup / Coroutine::cancel() 来实现。
- 调度器集中管理:所有协程都挂在 Swoole 的调度器 loop 上,生命周期是统一管理的。
👉 重点:不像 Go Context 那样自动级联取消,Swoole 协程更多是“调度器集中管理 + ID 定位 + 手动取消”。
3. 示例:Swoole 协程的超时管理
<?php
use Swoole\Coroutine;
use function Swoole\Coroutine\go;
go(function () {
{{LATEX:0}}chan = new Coroutine\Channel();
go(function () use ({{LATEX:1}}chan->push("任务完成");
});
{{LATEX:2}}chan->pop(2.0);
if ({{LATEX:3}}chan->errCode);
echo "超时,任务已取消\n";
} else {
echo "结果: {$result}\n";
}
});
这里:
- 用
Channel::pop(timeout) 等待结果,超时自动返回 false。
- 如果超时,可以用
Coroutine::cancel(cid) 手动取消另一个协程。
4. 跟 Golang Context 的对比
| 特性 |
Go Context |
Swoole go() |
| 创建方式 |
go func() |
go(function(){}) |
| 退出控制 |
ctx.Done() 自动传播级联取消 |
调度器集中管理,需要手工用 cancel() |
| 超时 |
context.WithTimeout 内建支持 |
chan->pop(timeout) 或 Timer 控制 |
| 生命周期传递 |
函数参数层层传 |
cid/全局调度器 ID 定位 |
| 编程风格 |
强制显式传递 ctx,少泄漏 |
灵活,但容易忘记取消 |
✅ 总结一下:
Swoole 的 go() 创建的协程本质上是 Swoole 内置调度器托管的协程,不会像 Go 那样有 Context 的层层传播机制。协程的生命周期管理靠:
- Coroutine ID (cid) 定位
- 超时/Channel 控制
- 显式调用
Coroutine::cancel
所以 如果你来自 Go 背景,会觉得 Swoole 协程的管理更接近“调度器集中调度 + 显式取消”,而不是 Context 的自动化传递。