go协程全局变量和局部变量
原文链接:http://www.zhoubotong.site/post/19.html
大家可能经常会用到类似如下代码片段:
package main import ( "fmt" "sync" "time" ) func main() { sli := []int{0, 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() }
打印输出:
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
结果是不是和想象的不一样?,主要原因出在协程这里,如果不使用协程,直接使用串行的方式,结果结合预期一致,比如:
package main import ( "fmt" "time" ) func main() { sli := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} for k, v := range sli { func() { time.Sleep(time.Second) fmt.Println(k, v) }() } }
打印输出:
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
那为什么上面使用携程的输出都是相同值?我们来解读下:
其中 k, v 是迭代变量,每次迭代都会给 k, v 赋值新的值,并且多个协程又同时调用了 k, v ,所以结果就串了,那携程怎么解决?解决方式我们可以定义一个局部变量。
package main import ( "fmt" "sync" "time" ) func main() { sli := []int{0, 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() }
k1, v1 是局部变量,每次循环,循环体内是不共享的,这也是为什么可以这样声明变量(k1 := k)。
或者通过传参的方式来固定下来,比如像下面这样:
package main import ( "fmt" "sync" "time" ) func main() { sli := []int{0, 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() }
这样输出就正常,比如输出如下:
0 0 5 5 2 2 3 3 4 4 1 1 9 9 6 6 8 8 7 7
无论从事什么行业,只要做好两件事就够了,一个是你的专业、一个是你的人品,专业决定了你的存在,人品决定了你的人脉,剩下的就是坚持,用善良專業和真诚赢取更多的信任。