3 回答

TA貢獻(xiàn)1775條經(jīng)驗(yàn) 獲得超11個(gè)贊
每次運(yùn)行都有新變量x := i,
這段代碼通過(guò)打印xgoroutine 內(nèi)部的地址很好地顯示了差異:
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
并構(gòu)建您的第二個(gè)示例go build -race并運(yùn)行它:
您將看到:WARNING: DATA RACE
這會(huì)很好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

TA貢獻(xiàn)1824條經(jīng)驗(yàn) 獲得超6個(gè)贊
一般規(guī)則是,不要在 goroutine 之間共享數(shù)據(jù)。在第一個(gè)示例中,您基本上為每個(gè) goroutine 提供了自己的 副本x
,然后他們按照到達(dá) print 語(yǔ)句的任何順序?qū)⑵浯蛴〕鰜?lái)。在第二個(gè)示例中,它們都引用了相同的循環(huán)變量,并且在它們中的任何一個(gè)打印它時(shí)遞增到 5。我不相信那里的輸出是有保證的,只是碰巧創(chuàng)建 goroutine 的循環(huán)完成得比 goroutine 本身到達(dá)打印部分的速度更快。

TA貢獻(xiàn)1831條經(jīng)驗(yàn) 獲得超10個(gè)贊
用簡(jiǎn)單的英語(yǔ)解釋有點(diǎn)困難,但我會(huì)盡力而為。
你看,每次你生成一個(gè)新的 goroutine 時(shí),都有一個(gè)初始化時(shí)間,不管它多么微不足道,它總是在那里。所以,在你的第二種情況下,整個(gè)循環(huán)在任何 goroutine 開(kāi)始之前就已經(jīng)完成了變量的 5 次遞增。當(dāng) goroutine 完成初始化時(shí),他們看到的只是最終的變量值,即 5。
但是,在您的第一種情況下, x 變量保留了 i 變量的副本,以便當(dāng) goroutine 啟動(dòng)時(shí), x get 傳遞給它們。請(qǐng)記住,這里是i
遞增的,而不是x
. x
是固定的。因此,當(dāng) goroutine 啟動(dòng)時(shí),它們會(huì)得到一個(gè)固定值。
- 3 回答
- 0 關(guān)注
- 302 瀏覽
添加回答
舉報(bào)