本文共 1218 字,大约阅读时间需要 4 分钟。
我们会经常性的使用如下片段
for k, v := range sli { go ...}
来看下面的例子
func main() { sli := []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9} wg := sync.WaitGroup{ } for k, v := range sli { wg.Add(1) go func() { time.Sleep(time.Second) fmt.Println(k, v) wg.Done() }() } wg.Wait()}
打印输出
8 98 98 98 98 98 98 98 98 9
结果和想象的不一样,主要原因出在协程这里,如果不使用协程,而是使用串行的方式,结果结合预期一致,比如
func main() { sli := []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9} for k, v := range sli { func() { time.Sleep(time.Second) fmt.Println(k, v) }() }}
打印输出
0 11 22 33 44 55 66 77 88 9
其中 k, v 是迭代变量,每次迭代都会给 k, v 赋值新的值,并且多个协程又同时调用了 k, v ,所以结果就串了,解决方式就是定义一个局部变量。
func main() { sli := []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9} wg := sync.WaitGroup{ } for k, v := range sli { wg.Add(1) k1 := k v1 := v go func() { time.Sleep(time.Second) fmt.Println(k1, v1) wg.Done() }() } wg.Wait()}
打印输出
4 51 22 38 97 85 66 70 13 4
k1, v1 是局部变量
,每次循环,循环体内是不共享的,这也是为什么可以这样声明变量(k1 := k
)。
或者通过传参的方式来固定下来
func main() { sli := []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9} wg := sync.WaitGroup{ } for k, v := range sli { wg.Add(1) go func(k, v interface{ }) { time.Sleep(time.Second) fmt.Println(k, v) wg.Done() }(k, v) } wg.Wait()}
转载地址:http://kjaui.baihongyu.com/