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 上,生命周期是统一管理的。
Context 那样自动级联取消,Swoole 协程更多是“调度器集中管理 + ID 定位 + 手动取消”。---
3. 示例:Swoole 协程的超时管理
<?php
use Swoole\Coroutine;
use function Swoole\Coroutine\go;
go(function () {
$cid = Coroutine::getCid();
$chan = new Coroutine\Channel();
// 启动耗时任务
go(function () use ($chan) {
Co::sleep(5); // 模拟耗时
$chan->push("任务完成");
});
// 超时等待 2 秒
$result = $chan->pop(2.0); // 设置超时时间
if ($result === false) {
Coroutine::cancel($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
---