协程数受限于可用内存、文件描述符限制(ulimit -n)及代码中隐式阻塞或资源泄漏;单机稳定运行50–100万goroutine可行,前提是IO非阻塞、任务有界、退出可控、内存与句柄充足。

协程数到底受什么限制?
Go 的 goroutine 本身没有硬编码上限,但实际能开多少,取决于三样东西:可用内存、文件描述符(ulimit -n)、以及你代码里有没有隐式阻塞或资源泄漏。
一台 8GB 内存的机器,按每个 goroutine 初始栈 2KB 算,理论可跑约 400 万;但别真这么算——真实服务里还有 HTTP 连接、数据库连接池、日志缓冲、GC 元数据等吃内存,保守点说,单机稳定跑 50–100 万 goroutine 是可行的,前提是其他资源没卡死。
常见错误现象:
-
runtime: goroutine stack exceeds 1000000000-byte limit:栈爆了,多半是递归没出口或 channel 死锁导致栈持续增长 -
too many open files:不是协程太多,而是你开了太多 TCP 连接、没关文件句柄、或ulimit -n没调高(建议至少设为 100000) - 程序变慢、GC 频繁:协程里做了同步 IO(比如没用
context.WithTimeout的http.Get),或者每协程都 new 大对象没复用
百万协程不是“开出来就行”,关键在调度和 IO 模式
Go 的 GMP 调度器能扛住百万级 goroutine,但前提是它们大多数时间处于「休眠」或「等待 IO」状态。一旦大量协程同时做 CPU 密集计算、或频繁抢占锁、或卡在同步系统调用上,M 线程就会打满,P 队列积压,反而拖垮性能。
使用场景决定你是否需要真开百万:
- HTTP 服务:标准
net/http默认每请求一个goroutine,10 万并发连接 ≈ 10 万goroutine,没问题 - 长连接网关(如 WebSocket):连接数即协程数,百万连接需百万协程,此时必须用
epoll/IO 多路复用(Go 已内置),且禁用阻塞读写 - 批量任务分发:别一股脑
go task()百万次,要用sync.Pool复用任务结构体,用带缓冲的chan控制投递节奏
实操建议:
- 启动前调大系统限制:
ulimit -n 1048576 - 用
runtime.GOMAXPROCS(0)让 Go 自动匹配 CPU 核心数(别硬写数字) - 每个协程处理完立刻退出,避免长期驻留;长时任务拆成小步 +
select响应ctx.Done() - 监控指标:看
runtime.NumGoroutine()是否持续上涨,配合pprof查泄漏点
为什么有人开到百万还 panic?典型踩坑点
不是 Go 不行,是人没管住资源:
集企业自助建站、网络营销、商品推广于一体的系统 功能说明: 1、系统采用Microsoft SQL Server大型数据库支持,查询数据库用的全是存储过程,速度和性能极好。开发环境是vs.net,采用4层结构,具有很好的可维护性和可扩冲性。 2、用户注册和登陆 未注册用户只具备浏览商品、新闻和留言功能;要采购商品,需接受服务协议并填写相关注册信息成为正式用户后方可进行,以尽可能减少和避免无效
for i := 0; i :闭包变量i共享,所有协程看到的是最后一个值 → 必须传参:go func(i int) { ... }(i)- 每个协程都新建
http.Client或sql.DB:连接池爆炸,OS 端口/内存先扛不住 → 改用全局单例或sync.Pool - 用无缓冲
chan做任务分发,但消费者太少或挂了:发送方全卡住,协程全阻塞 → 改用带缓冲通道,或加超时:select { case ch - 忘记回收:协程里开了 timer、ticker、goroutine 但没
Stop()或cancel()→ 它们会一直活到程序退出,偷偷吃资源
要不要上协程池?什么时候该用?
不用一上来就上 goroutine 池,Go 原生创建开销极低(纳秒级),池子主要解决两类问题:
- 频繁创建销毁带来的 GC 压力(比如每秒几万次短任务)
- 需要硬性限流防雪崩(比如 DB 写入不能超过 500 QPS)
实操建议:
- 简单服务,用
semaphore更轻量:var sem = make(chan struct{}, 1000),进协程前sem ,退出时 - 真要用池,推荐
panjf2000/ants或uber-go/goleak配合测试,别自己手撸带状态的池 - 池大小不是越大越好:设为 CPU 核心数 × 2~4 倍通常就够,再大只是增加调度抖动
真正难的不是“能不能开百万”,而是“开出去之后,怎么让它们不互相咬、不抢资源、不赖着不走”。内存够、句柄够、IO 非阻塞、任务有界、退出有路——这五条守住了,百万协程就是常态,不是彩蛋。









