簡體   English   中英

在goroutine中更新全局變量的不同行為

[英]Different behavior of updating global variable in goroutine

我有一個如下的程序。 它啟動NumberOfCPUs-1 goroutine,並且在每個goroutine內部僅更新全局變量x 輸出為x = 0

func main() {
    var x int
    threads := runtime.GOMAXPROCS(0)-1
    for i := 0; i < threads; i++ {
        go func() {
            for {
                x++
            }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println("x =", x)
}

如果我稍稍更改程序,如下所示:

func main() {
    var x int
    threads := runtime.GOMAXPROCS(0)
    for i := 0; i < threads; i++ {
        go func() {
            for {
                x++
                time.Sleep(0)
            }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println("x =", x)
}

x將是一些隨機的大值。

我認為這可能與goroutine調度程序有關。 在第一種情況下,goroutine的數量少於cpu內核的數量,因此可以使用所有現有goroutine執行main func。 由於每個goroutine內都沒有發生系統調用,I / O或通道通信,因此goroutine調度程序將無法工作。 並且由於goroutine不會被中斷,因此更新后的x沒有機會被寫回。

在第二種情況下,goroutines的數量等於cpu核心的數量,為了讓main func有運行的機會,我在update x之后放置了time.Sleep(0) 我認為每次goroutine調度程序切換goroutine時,更新后的x都會寫回到其原始存儲位置。

誰能證實我的想法? 有什么遺漏嗎?

謝謝。

您有多個goroutines共享同一個變量x ,但讀寫操作不同步。 您有數據競賽。 因此, x的結果是不確定的。 使用選項-race運行種族檢測器。 請參閱“ Go Race Detector”簡介


package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    var x int
    threads := runtime.GOMAXPROCS(0) - 1
    for i := 0; i < threads; i++ {
        go func() {
            for {
                x++
            }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println("x =", x)
}

輸出:

$ go run -race race1.go
==================
WARNING: DATA RACE
Read at 0x00c420084010 by goroutine 7:
  main.main.func1()
      /home/peter/gopath/src/race1.go:15 +0x3b

Previous write at 0x00c420084010 by goroutine 6:
  main.main.func1()
      /home/peter/gopath/src/race1.go:15 +0x54

Goroutine 7 (running) created at:
  main.main()
      /home/peter/gopath/src/race1.go:13 +0xb6

Goroutine 6 (running) created at:
  main.main()
      /home/peter/gopath/src/race1.go:13 +0xb6
==================
x = 24717968
Found 1 data race(s)
exit status 66

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    var x int
    threads := runtime.GOMAXPROCS(0)
    for i := 0; i < threads; i++ {
        go func() {
            for {
                x++
                time.Sleep(0)
            }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println("x =", x)
}

輸出:

$ go run -race race2.go
==================
WARNING: DATA RACE
Read at 0x00c4200140d0 by goroutine 7:
  main.main.func1()
      /home/peter/gopath/src/race2.go:15 +0x3b

Previous write at 0x00c4200140d0 by goroutine 6:
  main.main.func1()
      /home/peter/gopath/src/race2.go:15 +0x54

Goroutine 7 (running) created at:
  main.main()
      /home/peter/gopath/src/race2.go:13 +0xb3

Goroutine 6 (running) created at:
  main.main()
      /home/peter/gopath/src/race2.go:13 +0xb3
==================
==================
WARNING: DATA RACE
Read at 0x00c4200140d0 by goroutine 8:
  main.main.func1()
      /home/peter/gopath/src/race2.go:15 +0x3b

Previous write at 0x00c4200140d0 by goroutine 6:
  main.main.func1()
      /home/peter/gopath/src/race2.go:15 +0x54

Goroutine 8 (running) created at:
  main.main()
      /home/peter/gopath/src/race2.go:13 +0xb3

Goroutine 6 (running) created at:
  main.main()
      /home/peter/gopath/src/race2.go:13 +0xb3
==================
x = 14739962
Found 2 data race(s)
exit status 66

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM