协程退出不等于资源自动清理,必须显式调用close()等方法并用defer确保执行;避免复用全局连接,每个协程应持独立实例;co::cancel()需配合可中断i/o或co::yield()才能生效;优雅退出需监听onshutdown并主动等待协程完成。

协程退出时资源没释放,导致内存泄漏怎么办
协程退出不等于资源自动清理。Swoole 的 go 启动的协程一旦执行完或被取消,其内部打开的文件句柄、数据库连接、Redis 客户端、HTTP 客户端等都不会自动关闭——尤其是那些长期存活的对象(比如 Swoole\Coroutine\MySQL 实例)。
常见现象是:压测一段时间后 netstat -an | grep :3306 显示大量 ESTABLISHED 连接未释放,或 php -r "echo memory_get_usage();" 持续上涨。
- 必须显式调用对象的
close()或disconnect()方法,不能依赖析构函数(__destruct在协程退出时不一定触发) - 推荐在协程末尾用
defer注册清理逻辑,确保无论正常 return 还是异常退出都执行 - 避免在协程中复用全局连接对象;每个协程应持有独立的客户端实例(如
new Swoole\Coroutine\Redis())
使用 Co::cancel() 后协程还在跑?
Co::cancel() 只是给目标协程打上「已取消」标记,并不会立即中断执行。协程是否响应取消,取决于它当前是否处于可中断的系统调用点(如 co::sleep()、$redis->get()、$mysql->query())。
如果协程正在执行纯 PHP 计算(比如 for 循环或字符串处理),Co::cancel() 不会生效,直到下一次协程让出控制权。
- 在长循环中手动插入
Co::yield()或co::sleep(0),让出调度权以响应取消 - 检查关键 I/O 调用是否支持取消:新版 Swoole(v5.0+)中大部分协程客户端已支持,但自定义 socket 读写需配合
stream_select+Co::getCancelStatus()主动轮询 - 不要依赖
Co::getCid()判断协程是否存在——已取消但尚未退出的协程仍会返回有效 cid
如何让协程“等我做完再退”?
直接 exit 或抛出未捕获异常会导致整个进程退出,而 return 又可能让清理逻辑被跳过。真正可控的退出方式是「协作式退出」:让协程自己决定何时结束,并保证收尾动作完成。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 用
defer包裹清理代码,它会在协程函数返回前按后进先出顺序执行 - 若需等待异步操作(如最后一条日志写入、上报指标),用
Co::wait()等待子协程,但注意别形成死锁 - 避免在
defer中再启动新协程——新协程生命周期脱离原协程控制,可能变成孤儿协程
示例:
go(function () {
$redis = new Swoole\Coroutine\Redis();
$redis->connect('127.0.0.1', 6379);
defer(function () use ($redis) {
$redis->close(); // 必须显式 close
});
$redis->set('key', 'value');
// 协程自然 return,defer 自动触发
});
Worker 进程重启时,正在运行的协程怎么收尾
收到 SIGTERM 或调用 Server::shutdown() 时,Swoole 会尝试终止所有协程,但默认行为是「粗暴终止」:未执行完的协程直接销毁,defer 不触发,__destruct 不调用。
要实现优雅关闭,必须监听 shutdown 事件并主动等待协程退出。
- 在
onShutdown回调里调用Co::wait()或轮询Co::stats()中的 active_count - 设置合理的超时(如 3 秒),超时后强制退出,防止卡死
- 业务层应提供「可中断」的 shutdown hook,例如暴露一个
shutdown(): Promise方法供主流程 await
容易忽略的是:Swoole v4.8+ 提供了 Co::set(['enable_preemptive_scheduler' => true]),开启抢占式调度后,协程更频繁让出控制权,Co::cancel() 响应更快——但这会略微增加调度开销,生产环境需实测权衡。










