一、核心結(jié)構(gòu)體先貼一下
type Map struct {
mu Mutex //互斥鎖,用于鎖定dirty map
read atomic.Value //優(yōu)先讀map,支持原子操作,注釋中有readOnly不是說(shuō)read是只讀,而是它的結(jié)構(gòu)體。read實(shí)際上有寫的操作
dirty map[interface{}]*entry // dirty是一個(gè)當(dāng)前最新的map,允許讀寫
misses int // 主要記錄read讀取不到數(shù)據(jù)加鎖讀取read map以及dirty map的次數(shù),當(dāng)misses等于dirty的長(zhǎng)度時(shí),會(huì)將dirty復(fù)制到read
}
type readOnly struct {
m map[interface{}]*entry
amended bool // true if the dirty map contains some key not in m. // key在dirty中,不在read中
}
dirty map[interface{}]*entry
type entry struct {
// p points to the interface{} value stored for the entry.
//
// If p == nil, the entry has been deleted and m.dirty == nil.
//
// If p == expunged, the entry has been deleted, m.dirty != nil, and the entry
// is missing from m.dirty. // entry不存在 dirty中
//
// Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty
// != nil, in m.dirty[key].
//
// An entry can be deleted by atomic replacement with nil: when m.dirty is
// next created, it will atomically replace nil with expunged and leave
// m.dirty[key] unset.
//
// An entry's associated value can be updated by atomic replacement, provided
// p != expunged. If p == expunged, an entry's associated value can be updated
// only after first setting m.dirty[key] = e so that lookups using the dirty
// map find the entry.
p unsafe.Pointer // *interface{}
}
二、思考總結(jié)
核心思想是用空間換時(shí)間,用兩個(gè)map來(lái)存儲(chǔ)數(shù)據(jù),read和dirty,read支持原子操作,可以看作是dirty 的cache,dirty是更底層的數(shù)據(jù)存儲(chǔ)層
4種操作:讀key、增加key、更新key、刪除key的基本流程
讀key:先到read中讀取,如果有則直接返回結(jié)果,如果沒(méi)有或者是被刪除(有特殊value值可以判斷),則到dirty加鎖中讀取,如果有返回結(jié)果并更新miss數(shù)
增加key:直接增加到dirty中
更新key:先到read中看看有沒(méi)有,如果有直接更新key,如果沒(méi)有則到dirty中更新
刪除key:先到read中看看有沒(méi)有,如果有則直接更新為nil,如果沒(méi)有則到dirty中直接刪除
read的替換:當(dāng)read多次都沒(méi)有命中數(shù)據(jù),達(dá)到閾值,表示這個(gè)cache命中率太低,這時(shí)直接將整個(gè)read用dirty替換掉,然后dirty又重新置為nil,下一次再添加一個(gè)新key的時(shí)候,會(huì)觸發(fā)一次read到dirty的復(fù)制,這樣二者又保持了一致。
雖然read和dirty有冗余,但這些map的value數(shù)據(jù)是通過(guò)指針指向同一個(gè)數(shù)據(jù),所以盡管實(shí)際的value會(huì)很大,但是冗余的空間占用還是有限的。
總結(jié),如果對(duì)map的讀操作遠(yuǎn)遠(yuǎn)多于寫操作(寫操作包括新增和刪除key),那么sync.Map是很合適,能夠大大提升性能