Go goroutine做並行程序時,利用sync.Mutex
來限制只能有一個goroutine存取程式區塊。
範例環境:
- Go 1.18
未加Mutex鎖
下面主程式中發起了兩個goroutine執行inc()
函式來累加package level變數count
的值並印出goroutine名稱和count
值。最後用time.Sleep()
暫停避免提前結束。
main.go
package main
import (
"fmt"
"time"
)
var count int
func main() {
go inc("a")
go inc("b")
time.Sleep(time.Second) // prevent main goroutine end first
}
func inc(name string) {
count++
fmt.Printf("%s:%d\n", name, count)
}
由於goroutine是不保證順序的並行程序,所以可能印出以下結果。
結果一
b:2
a:1
執行順序可能為:
- a count++
- a print count (hold)
- b count++
- b print count
- a print count
結果二
b:2
a:2
執行順序可能為:
- a count++
- b count++
- b print count
- a print count
從以上結果可觀察到goroutine執行inc()
累加count
和印出的結果不同,則就是因為外部變數count
同時被多個goroutine存取且執行順序不定所導致。
加Mutex鎖
若希望goroutine執行inc()
累加count
和印出的值一致,則可用sync.Mutex.Lock()
及sync.Mutex.Unlock()
限制一段區塊只能有一個goroutine存取,待該goroutine離開後才能允許下一個goroutine存取。
下面在inc()
函式的前後加上sync.Mutex.Lock()
及sync.Mutex.Unlock()
限制兩著間的程式區塊只能有一個goroutine存取,所以count++
和印出的程式都只能由一個goroutine存取以此確保累加count
後和印出的值一致。
main.go
package main
import (
"fmt"
"sync"
"time"
)
var count int
var mu sync.Mutex
func main() {
go inc("a")
go inc("b")
time.Sleep(time.Second)
}
func inc(name string) {
mu.Lock()
count++
fmt.Printf("%s:%d\n", name, count)
mu.Unlock()
}
執行後可能印出以下結果。不論哪個goroutine先執行,count
累加和印出同時只能由一個goroutine存取。
結果ㄧ
goroutine a先執行inc()
。
a:1
b:2
執行順序為:
- a count++
- a print count
- b count++
- b print count
結果二
goroutine b先執行inc()
。
b:1
a:2
執行順序為:
- b count++
- b print count
- a count++
- a print count
Go Mutex的Lock
及Unlock
類似Java synchronized的概念。
沒有留言:
張貼留言