sync.Map
最后更新于:2022-04-02 04:47:02
在Go 1.6之前, 内置的map类型是部分goroutine安全的,并发的读没有问题,并发的写可能有问题。自go 1.6之后, 并发地读写map会报错,这在一些知名的开源库中都存在这个问题,所以go 1.9之前的解决方案是额外绑定一个锁,封装成一个新的struct或者单独使用锁都可以。
在Go1.9之前,go自带的map不是并发安全的,也就是说,我们需要自己再封装一层,给map加上把读写锁,比如像下面这样:
~~~
type MapWithLock struct {
sync.RWMutex
M map[string]Kline
}
~~~
用MapWithLock的读写锁去控制map的并发安全。
但是到了Go1.9发布,它有了一个新的特性,那就是sync.map,它是原生支持并发安全的map,不过它的用法和以前我们熟悉的map完全不一样,主要还是因为sync.map封装了更为复杂的数据结构,以实现比之前加锁map更优秀的性能。
使用
~~~
var mySMap sync.Map
~~~
sync.map就是1.9版本带的线程安全map,主要有如下几种方法:
~~~
Load(key interface{}) (value interface{}, ok bool)
通过提供一个键key,查找对应的值value,如果不存在,则返回nil。ok的结果表示是否在map中找到值
~~~
~~~
Store(key, value interface{})
这个相当于是写map(更新或新增),第一个参数是key,第二个参数是value
~~~
~~~
LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
通过提供一个键key,查找对应的值value,如果存在返回键的现有值,否则存储并返回给定的值,如果是读取则返回true,如果是存储返回false
~~~
~~~
Delete(key interface{})
通过提供一个键key,删除键对应的值
~~~
~~~
Range(f func(key, value interface{}) bool)
循环读取map中的值。
因为for ... range map是内置的语言特性,所以没有办法使用for range遍历sync.Map, 但是可以使用它的Range方法,通过回调的方式遍历。
~~~
应用:
~~~
package main
import (
"fmt"
"sync"
)
type userInfo struct {
Name string
Age int
}
var m sync.Map
func main() {
vv, ok := m.LoadOrStore("1", "one")
fmt.Println(vv, ok) //one false
vv, ok = m.Load("1")
fmt.Println(vv, ok) //one true
vv, ok = m.LoadOrStore("1", "oneone")
fmt.Println(vv, ok) //one true
vv, ok = m.Load("1")
fmt.Println(vv, ok) //one true
m.Store("1", "oneone")
vv, ok = m.Load("1")
fmt.Println(vv, ok) // oneone true
m.Store("2", "two")
m.Range(func(k, v interface{}) bool {
fmt.Println(k, v)
return true
})
m.Delete("1")
m.Range(func(k, v interface{}) bool {
fmt.Println(k, v)
return true
})
map1 := make(map[string]userInfo)
var user1 userInfo
user1.Name = "ChamPly"
user1.Age = 24
map1["user1"] = user1
var user2 userInfo
user2.Name = "Tom"
user2.Age = 18
m.Store("map_test", map1)
mapValue, _ := m.Load("map_test")
for k, v := range mapValue.(interface{}).(map[string]userInfo) {
fmt.Println(k, v)
fmt.Println("name:", v.Name)
}
}
~~~
~~~
package main
import (
"fmt"
"sync"
)
var myMap sync.Map
func main() {
// 增
myMap.Store("1", []string{"hi"}) //业务逻辑,其实两个都是string类型
myMap.Store(1, 11111)
// 查
if val, ok := myMap.Load("1"); ok {
fmt.Println("查", val)
}
// 改
myMap.Store("1", 2222222)
if val, ok := myMap.Load("1"); ok {
fmt.Println("改", val)
}
// 查找 or 存在返回,存在添加
if v, ok := myMap.LoadOrStore("22", "33333333"); ok {
fmt.Println("LoadOrStore", v)
}
// 删除
myMap.Delete("1")
// 遍历
f := func(key, value interface{}) bool {
fmt.Println("遍历", key, value)
return true
}
myMap.Range(f)
}
~~~
';