我正在学习Go,并试图了解其并发功能。

我有以下程序。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)

        x := i

        go func() {
            defer wg.Done()
            fmt.Println(x)
        }()

    }

    wg.Wait()
    fmt.Println("Done")
}

执行后,我得到:
4
0
1
3
2

这就是我想要的。但是,如果我对其进行一些修改:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)

        go func() {
            defer wg.Done()
            fmt.Println(i)
        }()

    }

    wg.Wait()
    fmt.Println("Done")
}

我得到的将是:
5
5
5
5
5

我不太了解两者之间的区别。谁能帮助解释这里发生的事情以及Go运行时如何执行此代码?

最佳答案

每次运行x := i时,您都有一个新变量,
通过在goroutine中打印x的地址,此代码很好地显示了差异:
The Go Playground:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        x := i
        go func() {
            defer wg.Done()
            fmt.Println(&x)
        }()
    }
    wg.Wait()
    fmt.Println("Done")
}

输出:
0xc0420301e0
0xc042030200
0xc0420301e8
0xc0420301f0
0xc0420301f8
Done

并使用go build -race构建第二个示例并运行它:
您将看到:WARNING: DATA RACE
这会很好The Go Playground:

//go build -race
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            fmt.Println(i)
        }(i)
    }
    wg.Wait()
    fmt.Println("Done")
}

输出:
0
4
1
2
3
Done

关于multithreading - Golang如何在goroutine之间共享变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39207608/

10-10 23:56