软件包中 的新Map类型sync是具有存储和删除的并发映射。多个goroutines可以同时调用Map的方法是安全的。
在新版本中官方是这样描述的:
The new Map type in the sync package is a concurrent map with amortized-constant-time loads, stores, and deletes. It is safe for multiple goroutines to call a Map's methods concurrently.
使用方法
1.9以前都是自己通过锁来处理map 的并发安全的并封装成新的struct暴露给外部使用的,一下代码是1.9的代码使用案例:
func main() {
list := map[string]interface{}{
"name": "田馥甄",
"birthday": "1983年3月30日",
"age": 34,
"hobby": []string{"听音乐", "看电影", "电视", "和姐妹一起讨论私人话题"},
"constellation": "白羊座",
}
var m sync.Map
for k, v := range list {
m.Store(k, v)
}
var wg sc.WaitGroup
wg.Add(2)
go func() {
m.Store("age", 22)
m.LoadOrStore("tag", 8888)
wg.Done()
}()
go func() {
m.Delete("constellation")
m.Store("age", 18)
wg.Done()
}()
wg.Wait()
m.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true
})
}
暴露出来了Map结构是开箱即用的,也可以声明这样的0值
var m sync.Map
sync包中暴露出来的map方法有:
func (m *Map) Load(key interface{}) (interface{},bool)
func (m *Map) Store(key, value interface{})
func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
func (m *Map) Delete(key interface{})
func (m *Map) Range(f func(key, value interface{}) bool)
内部实现
接下来分别分析一下上面暴露出来的方法的内部实现,先查看一下sync.Map结构(sync.Map结构中使用了atomic.Value作为并发安全的替代方法,因为在使用atomic.Value的时候 ,一旦Store被调用那么atomic.Value 就不能被复制,复制后会出现一些竞争问题,所以在使用sync.Map 的时候,在初始化之后也是不要复制sync.Map):
type Map struct {
mu sync.Mutex
read atomic.Value
dirty map[interface{}]*entry
misses int
}
func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
read, _ := m.read.Load().(readOnly)
e, ok := read.m[key]
if !ok && read.amended {
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
e, ok = read.m[key]
if !ok && read.amended {
e, ok = m.dirty[key]
m.missLocked()
}
m.mu.Unlock()
}
if !ok {
return nil, false
}
return e.load()
}
func (m *Map) Store(key, value interface{}) {
read, _ := m.read.Load().(readOnly)
if e, ok := read.m[key]; ok && e.tryStore(&value) {
return
}
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
m.dirty[key] = e
}
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
e.storeLocked(&value)
} else {
if !read.amended {
m.dirtyLocked()
m.read.Store(readOnly{m: read.m, amended: true})
}
m.dirty[key] = newEntry(value)
}
m.mu.Unlock()
}
func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
read, _ := m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
actual, loaded, ok := e.tryLoadOrStore(value)
if ok {
return actual, loaded
}
}
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
m.dirty[key] = e
}
actual, loaded, _ = e.tryLoadOrStore(value)
} else if e, ok := m.dirty[key]; ok {
actual, loaded, _ = e.tryLoadOrStore(value)
m.missLocked()
} else {
if !read.amended {
m.dirtyLocked()
m.read.Store(readOnly{m: read.m, amended: true})
}
m.dirty[key] = newEntry(value)
actual, loaded = value, false
}
m.mu.Unlock()
return actual, loaded
}
func (m *Map) Delete(key interface{}) {
read, _ := m.read.Load().(readOnly)
e, ok := read.m[key]
if !ok && read.amended {
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
e, ok = read.m[key]
if !ok && read.amended {
delete(m.dirty, key)
}
m.mu.Unlock()
}
if ok {
e.delete()
}
}
有疑问加站长微信联系(非本文作者)