因為golang的map和列表切片都是引用類型,且非線程安全的,所以在多個go routine中進行讀寫操作的時候,會產生“map read and map write“的panic錯誤。
某一些類型的對象,會有這種類似的set方法來寫數據,或者get方法來返回一個map:
func (this *object) Set(name, val) { this.Lock() defer this.Unlock() this.m[name] = val } func (this *object) Get() map[string]string { this.Lock() defer this.Unlock() return this.m }
如果會在多個go routine中通過該對象的Get()方法獲取到的map進行讀操作,並且在其他go routine中用Set()方法來寫操作,那么有可能會導致“map read and map write“的panic錯誤。
原因是Get方法獲取的map和Set方法操作的map是同一個map,如果讀寫線程在同一時刻操作這2個map,就會產生錯誤。
所以Get方法最好用這種方式返回map:
func (this *object) Get() map[string]string { this.Lock() defer this.Unlock() newm := make(map[string]string) for k, v := range this.m { newm[k] = v } return newm }
這樣每次Get獲取的map,其實是一個新的map,就可以不用考慮同時讀寫的問題了。