max_coroutine是单个Worker进程内协程数量的硬性上限,非全局限制;设worker_num=4、max_coroutine=10000时,理论峰值为40000协程,但受内存、FD等资源制约。

max_coroutine 是 Worker 进程级限制,不是全局或 Server 级
这个参数控制的是「单个 Worker 进程内最多能同时存在的协程数量」,不是整个 Swoole 服务的总和。比如你设了 worker_num => 4 和 max_coroutine => 10000,那理论上整机最多可并发 4 × 10000 = 40000 个协程(前提是内存和 FD 足够)。
常见误解是把它当成“全服务最大协程数”,结果压测时发现协程创建失败却查不到瓶颈——其实只是某个 Worker 已达上限,其他 Worker 还空闲。
- 它不作用于 Manager 进程或 Master 进程,只对 Worker 生效
- 每个 Worker 进程独立计数,互不影响
- 协程退出后计数自动减一,但若协程卡死(如未正确结束的
go())、或被阻塞在未 hook 的系统调用里,计数不会释放
默认值从 3000 变为 65536,但不能直接照搬
早期 Swoole 版本(max_coroutine 是 3000;4.5+ 默认升为 65536。这个变化容易让人误以为“现在可以随便开协程了”,但实际风险更大:
- 每个协程默认占用 8KB 栈空间,65536 × 8KB ≈ 512MB 内存仅用于协程栈(还不算堆内存)
- 高并发下若业务中存在
file_get_contents()、curl_exec()或未启用SWOOLE_HOOK_ALL,协程会假性“存活”却不让出控制权,导致计数卡住、新协程无法创建 - 某些低配机器(如 2GB 内存 VPS)设成 65536,可能刚启动就触发
PHP Fatal error: Allowed memory size exhausted
建议:上线前用 swoole_coroutine_stats() 观察 coroutine_peak_num,按峰值上浮 20% 设定,而非拍脑袋填 65536。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
运行时 set 和启动前 Coroutine::set 的效果差异
Swoole\Coroutine::set(['max_coroutine' => N]) 必须在任何协程创建前调用(通常放在 Server->start() 之前),否则无效;而 $server->set(['max_coroutine' => N]) 是 Server 构造时的配置项,同样需在 start() 前生效。
- 两者设置的是同一个底层值,最终都写入 Worker 的 coroutine scheduler 结构体
- 如果两个地方都设了,以
Coroutine::set()为准(它更底层,会覆盖 Server 配置) - 切勿在
go()回调里或请求处理中调用Coroutine::set()—— 此时调度器已初始化,修改无效且无报错
错误示例:
go(function () {
Swoole\Coroutine::set(['max_coroutine' => 100000]); // ❌ 完全没用
});
max_coroutine 不是并发能力的天花板,只是第一道闸门
它防的是“协程爆炸”,但真实并发瓶颈往往在别处:
- 数据库连接池大小(
max_connections)比max_coroutine更早卡住你 - 文件描述符限制(
ulimit -n)不够时,协程连 socket 都建不出来,报Too many open files - 未启用
Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL),导致sleep()、fopen()等同步调用阻塞整个 Worker,协程数没超限,但吞吐归零
真正要调的不是单一个 max_coroutine,而是配合 swoole_coroutine_stats() + strace -p {pid} -e trace=epoll_wait,read + 连接池监控,才能定位到底是“协程真多”,还是“协程假活”。

















