咱們在寫協程程序的時候,常常會碰到一個場景就是咱們要分發執行任務給不一樣的goroutine(簡稱gor),而後再把各個gor的處理結果彙總起來,這個時候就要注意gor的數據污染問題,咱們能夠經過閉包來防範各個gor之間的數據污染golang
下面的一個gor之間數據互相污染的範例shell
func main() { setMem := make(map[int]int) wg := sync.WaitGroup{} lk := sync.RWMutex{} for i := 0; i < 10; i++ { // 1 wg.Add(1) go func(wg *sync.WaitGroup) { // 2 fmt.Println("i ---- ", i) defer wg.Done() lk.Lock() setMem[i] = i * 2 lk.Unlock() }(&wg) } wg.Wait() fmt.Println("setMem 長度爲 ----------", len(setMem)) fmt.Println("setMem done ... ") }
這個的運行結果並不是如咱們所想,彙總了10個 gor的處理結果到 setMem 這個map中去安全
setMem 長度爲 ---------- 1 setMem done ...
緣由分析閉包
註釋1 由於main gor 和 go func 是同時在運行的, 因此main在賦值給 i 的同時, 2 接收到 i 的值並無鎖定 i , 而是接收到最新的for循環的值code
註釋2 沒有一個安全的內存區域儲存傳給當前 gor 的 i 值,因此形成數據污染協程
用閉包的原理去解決這個問題內存
func setM(wg *sync.WaitGroup, lk *sync.RWMutex, setMemx *map[int]int, i int) { defer wg.Done() fmt.Println("i ---- ", i) (*setMemx)[i] = i * 2 } func main() { setMemx := make(map[int]int) wg := sync.WaitGroup{} lk := sync.RWMutex{} for i := 0; i < 10; i++ { // 1 wg.Add(1) setM(&wg, &lk, &setMemx, i) // 2 } wg.Wait() fmt.Println("setMem 長度爲 ----------", len(setMemx)) fmt.Println("setMem done ... ") }
運行結果作用域
setMen 長度爲 ---------- 10 setMem done ...
註釋1 1 處依然是經過循環賦予 i 值 註釋2 2經過聲明獨立的func,來進行內存數據做用域鎖定,閉包的原理,防止數據污染it
因此運行的結果如咱們所想for循環