先看一段代碼安全
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup s := make([]int, 0, 1000) for i := 0; i < 1000; i++ { v := i wg.Add(1) go func() { s = append(s, v) wg.Done() }() } wg.Wait() fmt.Printf("%v\n", len(s)) }
結果架構
第一次:928 第二次:945 第三次:986 ……
多運行幾回你就會發現,slice長度並非1000,而是不停的在變,爲何呢?(若是這個代碼你沒法重現,你能夠嘗試將1000改成更大的數字)併發
由於append並非併發安全的。app
咱們舉一個簡單例子,好比,當A和B兩個協程運行append的時候同時發現s[1]這個位置是空的,他們就都會把本身的值放在這個位置,這樣他們兩個的值就會覆蓋,形成數據丟失。code
那該怎麼寫?最簡單的方式就是用鎖,貼一個例子協程
package main import ( "fmt" "sync" ) func main() { var ( wg sync.WaitGroup mutex sync.Mutex ) s := make([]int, 0, 1000) for i := 0; i < 1000; i++ { v := i wg.Add(1) go func() { mutex.Lock() s = append(s, v) mutex.Unlock() wg.Done() }() } wg.Wait() fmt.Printf("%v\n", len(s)) }
運行一下這個例子就會發現,s的長度老是1000。it
更多架構、PHP、GO相關踩坑實踐技巧請關注個人公衆號:PHP架構師import