go sync.Map源码解读

参考

package sync

import (
	"sync/atomic"
	"unsafe"
)

//	Map比起普通的map,是并发安全的;
//	Map针对2种情况做了优化:1)多读少写;2)多协程读、写,覆盖不同的key
//	比起map+mutex,Map空间换时间,用2个数据结构read,dirty减少锁的次数
//	read为只读,避免读写冲突
//	双重检测机制,且优先从read种读取,因为对read的读取不需要锁
//	动态调整,当misses次数多了后,dirty升级为read
//	延迟删除,删除一个键值只是打标记,在提升dirty时才清除删除的数据
type Map struct {
	mu Mutex

	//	read包含了map种可以安全并发访问的部分(使用/不使用mu)
	//	Load操作是安全的,store操作需要加mu
	read atomic.Value // readOnly

	//	dirty包含了map中需要加锁才能访问的key
	//	被置为enxugunged的entry不会保存在dirty中
	//	注意点,dirty为nil,read中的amended为false;dirty不为nil,read的amended为true
	dirty map[interface{}]*entry

	//	misses统计了read中读取key失败,需要加su判断dirty中是否存在key的次数
	//	当misses值 >= len(dirty),即加锁消耗达到了拷贝一整个dirty,将dirty升为read
	misses int
}


type readOnly struct {
	m       map[interface{}]*entry
	amended bool // true表dirty中包含read不存在的key
}

//	该指针用于标记dirty.map中的一个entry已删除;read中一个entry已删除,则置为nil
var expunged = unsafe.Pointer(new(interface{}))


type entry struct {
	//	p指向存储的interface
	//	p == nil 说明entry在read中以被删,但dirty中还在,可以直接更新值
	//	p == expunged 说明该entry不存在,在更新时需要加到entry
	//	else 该entry有效,且记录在read中,若dirty不空,则也在dirty中
	//	一个entry可以通过原子操作替换为nil来删除
	//	一个entry对应的值,可以通过原子操作来替换
	p unsafe.Pointer // *interface{}
}
//	为i新建一个entry,其中p保存i的地址
func newEntry(i interface{}) *entry {
	return &entry{p: unsafe.Pointer(&i)}
}

//	读取key的值
func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
	//	先尝试从read中读取
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	//	read中不存在,且dirty中包含该key
	if !ok && read.amended {
		m.mu.Lock()
		//	双重检测,因为加锁过程中dirty可能升为read,且dirty被置为nil
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]
		//	read不存在该key且dirty中包含key
		if !ok && read.amended {
			e, ok = m.dirty[key]
			//	记录一次未命中,足够多时dirty升级为read
			m.missLocked()
		}
		m.mu.Unlock()
	}
	//	仍不存在,返回
	if !ok {
		return nil, false
	}
	//	通过entry加载数据
	return e.load()
}

func (e *entry) load() (value interface{}, ok bool) {
	//	原子地重新读取数据
	p := atomic.LoadPointer(&e.p)
	//若为nil,expunged 说明已经被删
	if p == nil || p == expunged {
		return nil, false
	}
	//转为接口指针
	return *(*interface{})(p), true
}

//	Store sets the value for a key.
func (m *Map) Store(key, value interface{}) {
	//	先从read中读取,存在则尝试储存,成功则返回
	read, _ := m.read.Load().(readOnly)
	if e, ok := read.m[key]; ok && e.tryStore(&value) {
		return
	}

	m.mu.Lock()
	//	双重检测,因为加锁过程中dirty可能升为read,且dirty被置为nil
	read, _ = m.read.Load().(readOnly)
	if e, ok := read.m[key]; ok {//	read中存在key
		if e.unexpungeLocked() {//	标记为expunged(并重标为nil)
			//	此时说明dirty中不存在该key
			m.dirty[key] = e
		}
		//	修改entry的值,修改后read,dirty都修改了(因为保存的是entry的指针)
		e.storeLocked(&value)
	} else if e, ok := m.dirty[key]; ok {//	dirty中存在
		e.storeLocked(&value)
	} else {//	dirty中也没
		//	若dirty也没,说明dirty未新建或重建
		if !read.amended {
			//	新建dirty
			m.dirtyLocked()
			//	新建read, amended = true
			m.read.Store(readOnly{m: read.m, amended: true})
		}
		//	dirty中为该key新建entry
		m.dirty[key] = newEntry(value)
	}
	m.mu.Unlock()
}

//	尝试储存值(多协程操作,需要for使用CAS)
//	若已删除,返回false
//	未删除(包括nil),使用CAS赋值
func (e *entry) tryStore(i *interface{}) bool {
	for {
		p := atomic.LoadPointer(&e.p)
		if p == expunged {
			return false
		}
		if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
			return true
		}
	}
}

//	判断entry是否未expunged(此时mu已锁)
//	若为expunged,置为nil,返回true,表示不存在
//	否则返回false
func (e *entry) unexpungeLocked() (wasExpunged bool) {
	return atomic.CompareAndSwapPointer(&e.p, expunged, nil)
}

//	为该entry储存值i,为原子操作,调用时e.p不能为expunged
func (e *entry) storeLocked(i *interface{}) {
	atomic.StorePointer(&e.p, unsafe.Pointer(i))
}

//	若key存在,则返回对应的value,loaded为true
//	若key不存在,则存储给定的value值;loaded为false
func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
	//	先尝试从read中读取,若read中存在,则尝试loadorstore,成功则返回
	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()
	//	双重检测,因为加锁过程中dirty可能升为read,且dirty被置为nil
	read, _ = m.read.Load().(readOnly)
	if e, ok := read.m[key]; ok {//	read中存在key
		if e.unexpungeLocked() {//	标记为expunged(并重标为nil)
			//	此时说明dirty中不存在该key
			m.dirty[key] = e
		}
		//	更新后read,dirty中都是最新的
		actual, loaded, _ = e.tryLoadOrStore(value)
	} else if e, ok := m.dirty[key]; ok {//	dirty中存在

		//	只更新dirty
		actual, loaded, _ = e.tryLoadOrStore(value)
		m.missLocked()
	} else {//	dirty中也没
		//	若dirty也没,说明dirty未新建或重建
		if !read.amended {
			//	新建dirty
			m.dirtyLocked()
			//	新建read, amended = true
			m.read.Store(readOnly{m: read.m, amended: true})
		}
		//	dirty中为该key新建entry
		m.dirty[key] = newEntry(value)
		actual, loaded = value, false
	}
	m.mu.Unlock()

	return actual, loaded
}

//	tryLoadOrStore(多协程操作,此时mu锁未锁定)
//	若该条目未被删除,原子地读取value值,loaded=true,ok=true
//	若该条目已被删除(expunged或nil),则tryLoadOrStore函数不修改,直接返回,loaded==false,ok==false
func (e *entry) tryLoadOrStore(i interface{}) (actual interface{}, loaded, ok bool) {
	p := atomic.LoadPointer(&e.p)
	if p == expunged {
		return nil, false, false
	}
	if p != nil {
		return *(*interface{})(p), true, true
	}

	//	nil的情况
	ic := i
	for {
		//	CAS操作,赋值
		if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
			return i, false, true
		}
		p = atomic.LoadPointer(&e.p)
		if p == expunged {
			return nil, false, false
		}
		if p != nil {
			return *(*interface{})(p), true, true
		}
	}
}

// Delete deletes the value for a key.
func (m *Map) Delete(key interface{}) {
	//	优先从read中读取
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	if !ok && read.amended {
		m.mu.Lock()
		//	双重检测,因为加锁过程中dirty可能升为read,且dirty被置为nil
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]
		//	read不存在,但dirty存在
		if !ok && read.amended {
			//	锁定中,可以直接删
			delete(m.dirty, key)
		}
		m.mu.Unlock()
	}
	//	存在时一定存在于read中,只需在entry标记为nil
	if ok {
		e.delete()
	}
}
//	标记一个entry为删除(mu锁未加锁,需考虑多协程安全,本entry此时存在于read中)
func (e *entry) delete() (hadValue bool) {
	for {
		//	原子操作,重新读
		p := atomic.LoadPointer(&e.p)
		//	nil 表已被其他协程通过Delete()标记删除,不再操作
		//	expunged 表已被其他协程提升dirty为read时,标记删除,不再操作
		if p == nil || p == expunged {
			return false
		}
		// CAS操作,置为nil
		if atomic.CompareAndSwapPointer(&e.p, p, nil) {
			return true
		}
	}
}

//	遍历,基于f函数
func (m *Map) Range(f func(key, value interface{}) bool) {
	//	从read中获取
	read, _ := m.read.Load().(readOnly)
	//	已修改过,从dirty中获取
	if read.amended {
		m.mu.Lock()
		read, _ = m.read.Load().(readOnly)
		if read.amended {
			read = readOnly{m: m.dirty}
			m.read.Store(read)
			m.dirty = nil
			m.misses = 0
		}
		m.mu.Unlock()
	}

	for k, e := range read.m {
		v, ok := e.load()
		//	该值不存在了
		if !ok {
			continue
		}
		//	调用失败,终止
		if !f(k, v) {
			break
		}
	}
}
//	更新misses数,misseds >= len(dirty)时更新read\dirty
func (m *Map) missLocked() {
	m.misses++
	if m.misses < len(m.dirty) {
		return
	}
	m.read.Store(readOnly{m: m.dirty})
	m.dirty = nil
	m.misses = 0
}
//	更新dirty
func (m *Map) dirtyLocked() {
	if m.dirty != nil {
		return
	}

	read, _ := m.read.Load().(readOnly)
	m.dirty = make(map[interface{}]*entry, len(read.m))
	for k, e := range read.m {
		if !e.tryExpungeLocked() {
			m.dirty[k] = e
		}
	}
}
//	原子操作,判断entry的指针是否为nil(成功修改为expunged)
func (e *entry) tryExpungeLocked() (isExpunged bool) {
	p := atomic.LoadPointer(&e.p)
	for p == nil {
		if atomic.CompareAndSwapPointer(&e.p, nil, expunged) {
			return true
		}
		p = atomic.LoadPointer(&e.p)
	}
	return p == expunged
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值