go1.6之后map有了并发的安全检查,因此若是在并发环境中读写map就会报错html
func unsafeMap() { // 建立一个map对象 m := make(map[int]int) go func() { for { // 尝试读取数据 _ = m[1] } }() go func() { for { // 尝试写入数据 m[2] = 2 } }() // 阻塞 select {} } // output // fatalerror: concurrent map read and map write1.2 安全map
并发环境下面使用安全的mapjava
1.2.1 自定义结构体
// 经过内嵌读写锁的方式,保证咱们使用map的安全性 type MyMap struct{ sync.RWMutex m map[string]int // 须要一个并发的map[string]int类型 } // 封装一个建立map对象的方法 func NewMyMap()*MyMap{ smp:=new(MyMap) smp.m = make(map[string]int) return smp }
注意:咱们定义使用什么类型的map,那么就内置什么类型的map git
1.2.2 sync.Map
github
建立sync.Map对象golang
//1. 不须要经过map的方式进行建立,经过声明的方式或者new建立便可 var smap sync.Map //2. 经过new的方式建立 smap:=new(sync.Map)sync.Map 存储数据store方法api
//func (m *Map) Store(key, value interface{}) // key,value 都是接口类型,能够存储任何类型的数据 smap.Store(1,"MrSun")sync.Map读取数据安全
// func (m *Map) Load(key interface{}) (value interface{}, ok bool) // key: 键,value: 若是数据存在则返回对应的值,不存在则返回nil,ok: 表示值知否被找到 // 记得对数据断言处理 val,ok:=smap.Load(1)sync.Map,存在则读取,不存在存储并发
// func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) // key,value: 要存储的key与value //actual: 若是存在则返回存在的值,若是不存在则存储并返回存储的值 // laoded: 若是数据存在,则true,若是数据不存在则false actual, loaded := smap.LoadOrStore(1, "MrSun")sync.Map 遍历函数
// 建立map smap:=new(sync.Map) smap.LoadOrStore(1, "MrSun") smap.LoadOrStore(2, "hello") smap.LoadOrStore(3, "golang") smap.LoadOrStore(4, "bilili") //func (m *Map) Range(f func(key, value interface{}) bool) // 用户处理数据的回调函数,回调函数的参数是key,value,返回值是bool smap.Range(func(key, value interface{}) bool { smap.Store(5,"heihei") fmt.Println(key,value) return true })
// 注意:Range方法遍历的是map的副本 sync.Map 数据删除 // func (m *Map) Delete(key interface{}) // key: 要删除数据的key值 smap.Delete(1)
4核心之前内置的读写锁map性能要高高并发
4核心后,sync.Map 性能要高
The Map type is optimized for two common use cases:
when the entry for a given key is only ever written once but read many times, as in caches that only grow.
when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.
写少读多的状况
多goroutine,读、写、复写 不一样数据的状况 【没遇到过】
多核心状况使用
建议:没有特别要求的状况,二者均可以,go1.9之后建议直接使用sync.Map
采用分段锁机制,从而提升并发安全的性能
# github 星标 最高的一个 go get "github.com/orcaman/concurrent-map"
import "github.com/orcaman/concurrent-map" func concurrentMap() { mp:=cmap.New() // 存储值,key只能是string类型,value能够是任意类型 mp.Set("1","hello") mp.Set("2","golang") //val: 若是存在则返回值,不存在则返回nil // ok: 表示值若是存在则是true,若是不存在则是false val,ok:=mp.Get("2") if ok{ fmt.Println(val.(string)) } mp.Remove("1") _,ok=mp.Get("1") if !ok{ fmt.Println("data is not exist") } }