這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。Golang 1.9版本還沒有發布,大概在8月中旬發布,於是我看了下新版本都有哪些新東西,看來看去,看到了並發安全的Map於是我就看了一下源碼,本篇文章將帶領大家,看看新版本中 的並發安全的Map到底是個什麼樣子
軟體包中 的新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.Mapfor k, v := range list {m.Store(k, v)}var wg sc.WaitGroupwg.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.Mutexread atomic.Value dirty map[interface{}]*entrymisses 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() }}