在多個 goroutine 同時執行工作時,如果有存取到共用的資源,會造成每次的結果可能不一致.
下面的例子中每個 goroutine 都會對 sum + 1,但跑了很多次結果都會不一樣.
因為有可能有多個 goroutine 同時間取得的 sum 是一樣的.
package main
import (
"fmt"
"sync"
)
func main() {
var w sync.WaitGroup
var sum = 0
for i := 0; i < 1000; i++ {
w.Add(1)
go func() {
defer w.Done()
sum++
}()
}
w.Wait()
fmt.Println("final sum is", sum)
}
印出的值會不一定
final sum is 909
final sum is 944
final sum is 948
...
使用 sync.Mutex 來解決 race condition,再要改變共用變數的值前面加上 m.Lock(),
讓其他 goroutine 不能再對 sum 做加 1 的動作,直到該 goroutine 加 1 完後 m.Unlock(),
下個 goroutine 才可以繼續執行 sum++ 使用了 sync.Mutex 雖然可以避免 race condition
但卻會犧牲一點效能,所以使用上要注意
package main
import (
"fmt"
"sync"
)
func main() {
var w sync.WaitGroup
var m sync.Mutex
var sum = 0
for i := 0; i < 1000; i++ {
w.Add(1)
go func() {
defer w.Done()
m.Lock()
sum++
m.Unlock()
}()
}
w.Wait()
fmt.Println("final sum is", sum)
}
印出的值都會是 1000
final value is 1000
final value is 1000
...
也可以使用容量為 1 的 chennel 來確保每次最多一個 goroutine 存取共用變數,解決 race condition
package main
import (
"fmt"
"sync"
)
func main() {
var w sync.WaitGroup
ch := make(chan bool, 1)
var sum = 0
for i := 0; i < 1000; i++ {
w.Add(1)
go func() {
defer w.Done()
ch <- true
sum++
<-ch
}()
}
w.Wait()
fmt.Println("final sum is", sum)
}
印出的值都會是 1000
final value is 1000
final value is 1000
...