本文讲解如何正确实现切片元素的并发处理:使用 `sync.waitgroup` 安全启动 goroutine 并写入结果切片,避免闭包变量捕获错误和通道索引越界问题。
在 Go 中实现“对切片每个元素并发调用函数并汇总结果”,关键在于避免共享变量竞争、正确传递循环变量、确保主协程等待所有子协程完成。原代码中尝试用 []chan int 存储通道,但未初始化切片容量就直接索引赋值(chans[i] = ...),导致 panic;同时闭包内直接引用循环变量 counter 和 number,会因 goroutine 延迟执行而捕获到错误的终值(经典的“循环变量陷阱”)。
更简洁、高效且符合 Go 习惯的做法是:预先分配结果切片 + 使用 sync.WaitGroup 同步 + 显式传参避免闭包捕获问题。无需额外通道层,既降低复杂度,又提升性能。
以下是推荐的 parallel 函数实现:
func parallel(arr []int) []int {
outArr := make([]int, len(arr)) // 预分配,支持按索引安全写入
var wg sync.WaitGroup
for i, num := range arr {
wg.Add(1)
go func(index int, value int) {
defer wg.Done()
outArr[index] = double(value) // 直接写入对应位置
}(i, num) // 立即传值,避免闭包引用循环变量
}
wg.Wait() // 主协程阻塞等待所有 goroutine 完成
return outArr
}⚠️ 注意事项:
最终,parallel 函数执行时间约等于单次 double 耗时(500ms),而非串行累加(1500ms),真正实现了并行加速。该模式广泛适用于 I/O 密集型或计算密集型批量任务,是 Go 并发编程中的标准实践之一。