一、介绍
var a int
a := 0

二、for循环go协程作用域
1.咱们先看下最简略的for如下

package mainimport "fmt"func main() {   for i := 0; i < 2; i++ {      go func() {         fmt.Println(i)      }()   }}

下面的代码,最初没有输入。咱们的冀望输入 0 1 的欲望落空了,什么起因?
程序执行工夫图

如上图,咱们发现在下面的程序有2种状况
1.当主过程完结,goroutine2,goroutine3 都还没执行完,则没有输入。
2.状况2,如下图 goroutine2 执行完,输入了1 !!!!留神不是0!!!!

从下面学到的解决竞态4中计划,咱们用waitGroup阻塞主过程,改良代码如下:

package mainimport (   "fmt"   "sync")func main() {   wg := sync.WaitGroup{}   for i := 0; i < 2; i++ {      wg.Add(1)      go func() {         fmt.Println(i)         wg.Done()      }()   }   wg.Wait()}

输入如下:

22

终于两个goroutine都执行,但后果和咱们其余的0,1 齐全不一样。为啥?

当goroutine2,goroutine3 打印的时候,main goroutine 曾经将 i变成2了,而在整个for内,i是同一个变量。
此时就打印变成了2了。
2.for循环中go协程作用域
咱们看上面的示例代码

package mainimport (   "fmt"   "time")func main() {    // for 循环作用域开始    for i := 0; i < 2; i++ {      go func() {         fmt.Println(i)      }()   }//for 循环作用域完结   time.Sleep(time.Second)}

输入后果如下:

22

这是因为 i 的作用域的起因,咱们能够把for循环的代码重写如下:

func main() {   // for 循环作用域开始    var i int   for i = 0; i < 2; i++ {      go func() {         fmt.Println(i)      }()   }//for 循环作用域完结   time.Sleep(time.Second)}

这两种写法是等价,能够看进去 i 的作用域 为第2行到第7行,括号完结。此时就会呈现下面的都是2的状况。
那么咱们只有把传进goroutine的变量范畴变成goroutine之内就能解决这个问题了。
2.1 办法一goroutine加参数

func main() {   var i int   for i = 0; i < 2; i++ {      go func(j int) {         fmt.Println(j)      }(i)   }   time.Sleep(time.Second)}

输入如下:

01

2.2办法二放大变量范畴到goroutine的范畴内

func main() {   var i int   for i = 0; i < 2; i++ {      j := i      go func() {         fmt.Println(j)      }()   }   time.Sleep(time.Second)}

3.变量范畴革新代码革新如下

package mainimport (   "fmt"   "sync")func main() {   wg := sync.WaitGroup{}   for i := 0; i < 2; i++ {      wg.Add(1)      go func(j int) {         fmt.Println(j)         wg.Done()      }(i)   }   wg.Wait()}

输入

10

执行如下,此次是 goroutine3 先打印了,而后才是 goroutine2

阐明 for goroutine 中的执行程序是 无序的 ,业务中做的时候须要理解。这种无序性,如果业务须要有程序
最初用线性阻塞的编程,缩小用并发。