goroutine 非万能,需匹配任务类型:i/o等待或可分割计算任务适合,并发纯cpu循环或小数据串行处理反而降低性能。

goroutine 不是性能银弹,盲目增加数量反而拖慢程序——关键在控制并发粒度与资源匹配。
什么时候该用 goroutine?
不是所有耗时操作都适合并发:I/O 等待(如 HTTP 请求、文件读写、数据库查询)或计算密集但可分割的任务才值得开 goroutine。纯 CPU 循环、小数据量串行处理加 goroutine 反而引入调度开销。
- 适合:
http.Get批量调用、日志异步写入、多路消息处理 - 不适合:
for i := 0; i 这类微小计算 - 注意:Go 运行时默认复用 OS 线程,
runtime.GOMAXPROCS控制的是 P 的数量,不是线程数;通常保持默认(等于 CPU 核心数)即可,除非明确遇到 P 阻塞瓶颈
如何避免 goroutine 泄漏?
泄漏常发生在未关闭的 channel、无超时的阻塞等待、或长生命周期 goroutine 持有短生命周期资源。最典型的是忘记用 select + timeout 或 context.WithTimeout。
- HTTP 请求务必设超时:
http.Client{Timeout: 5 * time.Second} - 从 channel 读取前,确认发送方会关闭它;否则用
select配合default或timeout - 启动长期运行 goroutine 时,用
context.Context传递取消信号,避免“孤儿 goroutine”
channel 缓冲区大小怎么选?
零缓冲 channel 是同步点,会强制 goroutine 协作等待;有缓冲则提供解耦和背压缓冲能力,但缓冲区过大可能掩盖设计问题或吃光内存。
立即学习“go语言免费学习笔记(深入)”;
- 生产者消费者节奏稳定 → 缓冲大小 ≈ 单次批量数(如
make(chan int, 128)) - 需严格顺序/流控 → 用零缓冲
make(chan int),靠阻塞自然限速 - 不确定负载 → 先用小缓冲(32 或 64),配合
len(ch)监控堆积,再按需调整 - 切忌:
make(chan int, 1000000)—— 这不是优化,是延迟暴露内存问题
sync.Pool 能不能随便用?
它只对高频创建销毁、结构体大小稳定、且能安全复用的对象有价值;误用会导致内存不释放、数据残留或竞态。
- 适用:
[]byte、bytes.Buffer、自定义 parser 结构体 - 不适用:含指针字段未重置的对象、带回调函数的实例、任何含外部状态的类型
- 必须重置:
Pool.New返回的对象,在Get后要手动清空字段,否则上次残留数据可能被下个 goroutine 读到 - 别依赖它做对象生命周期管理 —— 它只是提示 GC “这个对象可能还会用”,不保证一定复用
真正卡性能的地方往往不在 goroutine 数量,而在锁竞争、channel 阻塞链、或未复用的内存分配。先用 go tool pprof 看 CPU 和 goroutine profile,再决定在哪加并发、加多少、加完怎么收口。











