go學習筆記-goroutine競爭狀態

若是兩個或者多個 goroutine在沒有相互同步狀態的狀況下同時訪問某個資源,而且同時對這個資源進行讀寫的時候,對於這個資源就處於相互競爭狀態(race candition)。下面來看一個相互競爭的例子。
var number int
var wait sync.WaitGroup
func main()  {
    wait.Add(2)
    go updateNumber(20000)//加20000
    go updateNumber(30000)//加30000
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    for i:=0;i<addNumber ;i++  {
        number ++
    }
    wait.Done()
}

上面這個例子,咱們指望獲得的值應該是500000,可是咱們最後獲得值,並非500000,並且每次獲得的結果是不同的。這是爲何呢?由於在兩個goroutine中沒有同步number的當前值,就會存在兩個goroutinenumber值重複賦值的問題,形成值覆蓋。這樣就得不到咱們預期的結果。安全

上面的例子咱們能夠看到,若是沒有對競爭的資源進行有效的管理以及合理的處理,併發程序就會變的很複雜,而且會產生一些意想不到的錯誤。因此咱們須要對競爭資源進行管理來避免這些問題。 Go中提供一些傳統的方式來處理這類問題
原子函數 atomic
原子函數可以以很底層的加鎖機制來同步訪問整型變量和指針,咱們可使用原子函數來處理競爭問題。
var number int32
var wait sync.WaitGroup
func main()  {
    wait.Add(2)
    go updateNumber(20000)
    go updateNumber(30000)
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    defer wait.Done()
    for i:=0;i<addNumber ;i++  {
        atomic.AddInt32(&number,1)
    }

}

這裏咱們使用了atmoic包的AddInt32 函數。這個函數會同步整型值的加法,
方法是強制同一時刻只能有一個goroutine 運行並完成這個加法操做。當goroutine試圖去調用任
何原子函數時,這些goroutine 都會自動根據所引用的變量作同步處理。atmoic包中還提供了LoadStore方法,對資源進行安全的讀與寫。併發

互斥鎖 mutex
另外一種方式是建立一個互斥鎖來鎖住一個區域,來保證同一個資源不會被同時修改或者使用。保證當前只有一個 goroutine在執行當前區域的代碼。
var (
    number int32
    wait sync.WaitGroup
    mutex sync.Mutex
    )
func main()  {
    wait.Add(2)
    go updateNumber(20000)
    go updateNumber(30000)
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    defer wait.Done()
    for i:=0;i<addNumber ;i++  {
        mutex.Lock() // 加鎖
        number++;
        mutex.Unlock() //釋放鎖
    }
}

上面的代碼片斷,在Number改變的先後對當前區域加鎖,最後也能獲得咱們的目的,可是這樣的會話,每次在number變動的時候,都會建立鎖與釋放鎖,會對性能產生很大的影響。其實咱們能夠在for循環區域來加鎖。函數

func updateNumber(addNumber int)  {
    defer wait.Done()
    mutex.Lock() // 加鎖
    for i:=0;i<addNumber ;i++  {
        number++;
    }
    mutex.Unlock() //釋放鎖
}

後面這種形式的效率明顯是要比第一種高不少的。因此咱們程序有使用互斥鎖的話,須要考慮加鎖的粒度問題。性能

雖然上面上面兩種方式也能夠解決競爭問題,可是在 go中有一種更好的方式來解決這個問題,那就是 goroutine的好兄弟 channel。因爲 channel的內容比較多,因此我將單獨寫一個筆記來記錄這方面的問題。期待下一篇的更新

期待一塊兒交流

file

相關文章
相關標籤/搜索