前言
go 并发访问map是不安全的, 会出现未定义的错误导致程序退出…坑总得踩一踩才会知道
例子
先写一个错误的
package main import "fmt" func test() map[string]interface{}{ taskList := []string{"a", "b"} result := make(map[string]interface{}) for _, task := range taskList { go func(task string) { switch task { case "a": result["a"] = "xiaofei" case "b": result["b"] = "ceshi" } }(task) } return result } func main() { for a := 0; a < 1000; a++ { fmt.Println(test()) } }
返回结果
上面代码有两个问题, 第一个是没有阻塞go程, 第二个就是并发访问map了
正确的写法
package main import ( "fmt" "sync" ) // 使用读写锁 sync.RWMutex type NewMap struct { lock *sync.RWMutex sm map[interface{}]interface{} } func (m *NewMap) Set(k interface{}, v interface{}) bool { m.lock.Lock() defer m.lock.Unlock() m.sm[k] = v return true } func test() map[interface{}]interface{} { taskList := []string{"a", "b"} xf := &sync.WaitGroup{} result := NewMap{ lock: new(sync.RWMutex), sm: make(map[interface{}]interface{}), } for _, task := range taskList { xf.Add(1) go func(task string) { defer xf.Done() switch task { case "a": result.Set("a", "xiaofei") case "b": result.Set("b", "ceshi") } }(task) } xf.Wait() return result.sm } func main() { for a := 0; a < 100; a++ { fmt.Println(test()) } }
建议把这个map做一个基类方法, 所有的方法封装一下直接用就ok了;