前言
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了;