亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么這個程序中存在競爭條件?

為什么這個程序中存在競爭條件?

Go
冉冉說 2021-06-10 14:39:35
我正在查看Golang文檔中的典型數據競爭,我不太明白為什么這個程序會出現問題:func main() {    var wg sync.WaitGroup    wg.Add(5)    for i := 0; i < 5; i++ {        go func() {            fmt.Println(i) // Not the 'i' you are looking for.            wg.Done()        }()    }    wg.Wait()}它5, 5, 5, 5, 5會在我希望它打印時打印0, 1, 2, 3, 4(不一定按此順序)。在我看來,當 goroutine 在循環內創建時, 的值i是已知的(例如,可以log.Println(i)在循環開始時執行 a并查看預期值)。所以我希望 goroutinei在它被創建時捕獲它的值并在以后使用它。顯然這不是正在發生的事情,但為什么呢?
查看完整描述

3 回答

?
烙印99

TA貢獻1829條經驗 獲得超13個贊

您的函數文字i從外部范圍引用。如果您請求 的值i,您將獲得當前的任何值i。為了使用iGo 例程創建時的值,請提供一個參數:


func main() {

    var wg sync.WaitGroup

    wg.Add(5)

    for i := 0; i < 5; i++ {

        go func(i int) {

            fmt.Println(i)

            wg.Done()

        }(i)

    }

    wg.Wait()

}


查看完整回答
反對 回復 2021-06-21
?
慕萊塢森

TA貢獻1810條經驗 獲得超4個贊

該變量i未在函數字面量中聲明,因此它成為閉包的一部分。理解閉包的一個簡單方法是考慮如何實現它們。簡單的解決方案是使用指針。你可以認為函數字面量被編譯器改寫成一些


func f123(i *int) {

        fmt.Println(*i)

        wg.Done            

}

  • 在調用此函數時,通過 go 語句,將i變量的地址傳遞給被調用的 f123(編譯器生成的示例名稱)。

  • 您可能正在使用默認的 GOMAXPROCS==1,因此 for 循環在沒有任何調度的情況下執行 5 次,因為該循環沒有 I/O 或其他“調度點”,例如通道操作。

  • 當循環以 結束時i == 5,wg.Waitfinally 會觸發五個準備運行的 goroutines(對于 f123)的執行。他們當然都有指向同一個整數變量的相同指針i。

  • 現在每個 goroutine 都看到相同的i值 5。

當 GOMAXPROCS > 1 運行時,或者當循環產生控制時,您可能會得到不同的輸出。這也可以通過例如runtime.Gosched來完成。



查看完整回答
反對 回復 2021-06-21
  • 3 回答
  • 0 關注
  • 222 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號