zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    aa
    MySQL5.8下载及安装——免安装版
    eclipse中修改项目名
    利用kibana学习 elasticsearch restful api (DSL)
    https://www.cnblogs.com/shwee/p/9084535.html
    springboot+mybatis实现动态切换数据源
    docker-machine命令安装
    Docker 安装 RabbitMq
    yum 找不到程序,yum更换国内阿里源
    CentOS安装etcd和flannel实现Docker跨物理机通信
  • 原文地址:https://www.cnblogs.com/phpper/p/14258874.html
Copyright © 2011-2022 走看看