輕鬆檢測Golang併發的資料競爭

大彬發表於2019-02-16

Golang中我們使用Channel或者sync.Mutex等鎖保護資料,有沒有一種機制可以檢測程式碼中的資料競爭呢?

背景知識

資料競爭是併發情況下,存在多執行緒/協程讀寫相同資料的情況,必須存在至少一方寫。另外,全是讀的情況下是不存在資料競爭的。

使用race檢測資料競爭

go build有個標記race可以幫助檢測程式碼中的資料競爭。

➜  awesome git:(master) ✗ go help build
//.... omit
-race
        enable data race detection.
        Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.

下面舉個例子:

package main

import "fmt"

func main() {
    i := 0

    go func() {
        i++ // write i
    }()

    fmt.Println(i) // read i
}

測試方法:

➜  awesome git:(master) ✗ go build -race hi.go
➜  awesome git:(master) ✗ ./hi
0
==================
WARNING: DATA RACE
Write at 0x00c00009c008 by goroutine 6:
  main.main.func1()
      /Users/mac/go/src/github.com/mac/awesome/hi.go:9 +0x4e

Previous read at 0x00c00009c008 by main goroutine:
  main.main()
      /Users/mac/go/src/github.com/mac/awesome/hi.go:12 +0x88

Goroutine 6 (running) created at:
  main.main()
      /Users/mac/go/src/github.com/mac/awesome/hi.go:8 +0x7a
==================
Found 1 data race(s)
exit status 66

提示示例程式碼存在1處資料競爭,說明了資料會在第9行寫,並且同時會在12行讀形成了資料競爭。

當然你也可以使用go run一步到位:

➜  awesome git:(master) ✗ go run -race hi.go
0
==================
WARNING: DATA RACE
Write at 0x00c000094008 by goroutine 6:
  main.main.func1()
      /Users/shitaibin/go/src/github.com/shitaibin/awesome/hi.go:9 +0x4e

Previous read at 0x00c000094008 by main goroutine:
  main.main()
      /Users/shitaibin/go/src/github.com/shitaibin/awesome/hi.go:12 +0x88

Goroutine 6 (running) created at:
  main.main()
      /Users/shitaibin/go/src/github.com/shitaibin/awesome/hi.go:8 +0x7a
==================
Found 1 data race(s)
exit status 66

如果這篇文章對你有幫助,請點個贊/喜歡,讓我知道我的寫作是有價值的,感謝。

相關文章