go协程全局变量和局部变量

原文连接:http://www.zhoubotong.site/post/19.html

html

你们可能常常会用到相似以下代码片断:post

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()
}

打印输出:spa

9 9
9 9
9 9
9 9
9 9
9 9
9 9
9 9
9 9
9 9

结果是否是和想象的不同?,主要缘由出在协程这里,若是不使用协程,直接使用串行的方式,结果结合预期一致,好比:code

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 ,因此结果就串了,那携程怎么解决?解决方式咱们能够定义一个局部变量。htm

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)。blog

或者经过传参的方式来固定下来,好比像下面这样:get

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()
}

这样输出就正常,好比输出以下:it

0 0
5 5
2 2
3 3
4 4
1 1
9 9
6 6
8 8
7 7
相关文章
相关标签/搜索