在Goroutine函数中以值传递数组无效果的技术问题
嘿,来帮你搞定Goroutine里数组传递的问题!
首先得明确一个Go里很容易搞混的点:你代码里的[][]int是切片(不是数组),切片是引用类型,但值传递的时候传的是切片结构体的副本——这就导致了几种常见的“没效果”场景,结合你的代码来拆解:
为什么你的函数没产生预期效果?
1. 你可能在函数里修改了切片本身,而不是底层数组
如果DoSomethingWithArray里有重新分配切片(比如mapArray = make(...))或者用append修改长度的操作,这些改动只会作用在函数内部的切片副本上,外部的原切片完全不会受影响——因为副本和原切片是两个独立的结构体,只是一开始指向同一个底层数组而已。
2. Goroutine没同步,你提前读取了结果
就算你正确修改了底层数组,要是启动Goroutine后立刻去检查数组,大概率Goroutine还没来得及执行,自然看不到效果。
针对你的代码的修复方案
方案一:传递切片指针(彻底避免歧义)
如果你需要在函数里调整切片的长度、重新分配,或者就是不想纠结引用/值传递的细节,直接传切片的指针就行:
func DoSomethingWithArray(aSize, threadID int, mapArray *[][]int) { var start, end int switch threadID { case 0: start = 0 end = aSize // 解引用指针后修改底层数组 for y := start; y < end; y++ { for x := 0; x < aSize; x++ { (*mapArray)[y][x] = 1 } } case 1: // 补充你的分片逻辑,比如处理后半段 start = aSize/2 end = aSize for y := start; y < end; y++ { for x := 0; x < aSize; x++ { (*mapArray)[y][x] = 2 } } } } // 启动Goroutine时传指针 go DoSomethingWithArray(size, 0, &myArray)
方案二:直接修改底层数组(不用指针也能行)
如果你的逻辑只是修改切片里的元素值,其实不用传指针——因为切片副本和原切片指向同一个底层数组。只要别在函数里重新分配切片就行,比如修正你的函数:
func DoSomethingWithArray(aSize, threadID int, mapArray [][]int) { var start, end int switch threadID { case 0: start = 0 end = aSize // 直接修改元素,这个改动会同步到原切片 for y := start; y < end; y++ { for x := 0; x < aSize; x++ { mapArray[y][x] = 1 } } case 1: // 补充你的分片逻辑 start = 0 end = aSize/2 for y := start; y < end; y++ { for x := 0; x < aSize; x++ { mapArray[y][x] = 2 } } } }
方案三:加同步机制,等Goroutine跑完再看结果
如果是同步问题,用sync.WaitGroup等所有Goroutine执行完再处理结果:
import ( "fmt" "sync" ) func main() { size := 5 myArray := Empty2DArray(size) var wg sync.WaitGroup // 假设启动2个Goroutine wg.Add(2) go func() { defer wg.Done() DoSomethingWithArray(size, 0, myArray) }() go func() { defer wg.Done() DoSomethingWithArray(size, 1, myArray) }() wg.Wait() // 等所有Goroutine干完活 // 现在打印就能看到预期效果了 for _, row := range myArray { fmt.Println(row) } }
额外提一句你的Empty2DArray函数
这个函数写的没问题,它为每一行都单独分配了切片,避免了二维切片常见的“所有行共享同一个底层数组”的坑,这点做得很好!
内容的提问来源于stack exchange,提问作者Gabriel
相关产品推荐
相关产品推荐

