go for循环性能问题源于内存分配、重复计算和错误抽象:需预分配切片容量、缓存len()等不变值、谨慎处理range取地址、避免小任务过度并发,并关注算法复杂度。

Go 的 for 循环本身没有“慢”,慢的是你写法里藏着的内存分配、重复计算和错误抽象。
预分配切片容量,避免 append 频繁扩容
循环中反复 append 到未预设容量的切片,会触发多次底层数组复制——每次扩容约 1.25 倍,旧数据要 memcpy,GC 也要盯上这些临时内存。
- ❌ 错误写法:
var result []int; for i := 0; i - ✅ 正确做法:提前用
make([]int, 0, 10000)分配好底层数组,append就只是填数,零拷贝 - 场景:构建返回 slice、日志批量收集、HTTP 批量响应组装
别在循环里调 len()、cap() 或方法调用
Go 编译器不会帮你把不变的长度提取到循环外——它忠实地每次执行 len(slice),哪怕 slice 根本没变。对大 slice 来说,这开销虽小但可测。
- ❌ 错误写法:
for i := 0; i - ✅ 正确做法:
n := len(data); for i := 0; i - 同理:如果循环体里反复调
user.GetName()且结果不变,就提出来缓存为局部变量
range 遍历切片比索引访问更安全,但取地址要小心
for range 编译后和手写索引循环性能几乎一致(Go 1.21+ 已优化),且自动防越界;但它返回的 v 是值拷贝,生命周期复用——直接取 &v 会得到同一地址。
立即学习“go语言免费学习笔记(深入)”;
- ❌ 危险写法:
for _, v := range nums { ptrs = append(ptrs, &v) }→ 全是指向最后一个v的指针 - ✅ 安全方案一:
for i := range nums { ptrs = append(ptrs, &nums[i]) } - ✅ 安全方案二:
for _, v := range nums { v := v; ptrs = append(ptrs, &v) }(显式创建新变量)
并发不是银弹,别为小循环硬套 goroutine
启动一个 goroutine 成本约几百纳秒,调度、channel 收发、锁竞争都可能吃掉并行收益。只有当单次迭代耗时 >10μs 且无共享状态时,并发才大概率赢。
- ❌ 过度并发:
for i := range data { go process(data[i]) }(data 长度 100,process 耗时 1μs)→ 可能比串行还慢 - ✅ 合理分块:
chunkSize := (len(data) + 3) / 4; for i := 0; i - 关键:用
sync.WaitGroup等待,别让 goroutine 泄漏;用runtime.GOMAXPROCS控制并发度上限
真正卡住 Go 循环性能的,往往不是语法本身,而是你没意识到那个 bytes.Buffer{} 在循环里被新建了 10 万次,或者那个 map 查找被塞进了三层嵌套循环里——算法复杂度没动,光靠换循环写法救不了命。










