var expunged = unsafe.Pointer(new(interface{})) type Map struct type readOnly struct type entry struct func (m *Map) Load(key interface{}) (value interface{}, ok bool) func (m *Map) Store(key, value interface{}) func (m *Map) Delete(key interface{}) func (m *Map) Range(f func(key, value interface{}) bool)
這裏要重點關注readOnly.amended
、Map.misses
和entry.p
的數值狀態, 拓撲圖中,多處用於走勢判斷.
接下來詳細列出結構體的代碼和註釋, 方便閱讀理解拓撲圖.segmentfault
type Map struct { //互斥鎖,用於鎖定dirty map mu Mutex //優先讀map,支持原子操做,註釋中有readOnly不是說read是隻讀,而是它的結構體。read實際上有寫的操做 read atomic.Value // dirty是一個當前最新的map,容許讀寫 dirty map[interface{}]*entry // 主要記錄read讀取不到數據加鎖讀取read map以及dirty map的次數,當misses等於dirty的長度時,會將dirty複製到read misses int } // readOnly 主要用於存儲,經過原子操做存儲在 Map.read 中元素。 type readOnly struct { // read的map, 用於存儲全部read數據 m map[interface{}]*entry // 若是數據在dirty中但沒有在read中,該值爲true,做爲修改標識 amended bool } // entry 爲 Map.dirty 的具體map值 type entry struct { // nil: 表示爲被刪除,調用Delete()能夠將read map中的元素置爲nil // expunged: 也是表示被刪除,可是該鍵只在read而沒有在dirty中,這種狀況出如今將read複製到dirty中,即複製的過程會先將nil標記爲expunged,而後不將其複製到dirty // 其餘: 表示存着真正的數據 p unsafe.Pointer // *interface{} }
sync.Map的原理很簡單,使用了空間換時間策略,經過冗餘的兩個數據結構(read、dirty),實現加鎖對性能的影響。
經過引入兩個map將讀寫分離到不一樣的map,其中read map提供併發讀和已存元素原子寫,而dirty map則負責讀寫。
這樣read map就能夠在不加鎖的狀況下進行併發讀取,當read map中沒有讀取到值時,再加鎖進行後續讀取,並累加未命中數。
當未命中數大於等於dirty map長度,將dirty map上升爲read map。
從結構體的定義能夠發現,雖然引入了兩個map,可是底層數據存儲的是指針,指向的是同一份值。
參考文檔:
你不得不知道的sync.Map源碼分析數據結構