sync.Map
是一个并发安全的MAP实现.sync.Map
中的原始 map 类型实际上是map[any]*entry
.
当我们调用Map.LoadOrStore
并且条目存在时,将调用entry.tryLoadOrStore
,并且以下是该函数的代码
func (e *entry) tryLoadOrStore(i any) (actual any, loaded, ok bool) {
p := e.p.Load()
if p == expunged {
return nil, false, false
}
if p != nil {
return *p, true, true
}
// Copy the interface after the first load to make this method more amenable
// to escape analysis: if we hit the "load" path or the entry is expunged, we
// shouldn't bother heap-allocating.
ic := i
for {
if e.p.CompareAndSwap(nil, &ic) {
return i, false, true
}
p = e.p.Load()
if p == expunged {
return nil, false, false
}
if p != nil {
return *p, true, true
}
}
}
这是另一个函数trySwap
,当我们调用Swap
或Store
时,这个函数也会被调用.
func (e *entry) trySwap(i *any) (*any, bool) {
for {
p := e.p.Load()
if p == expunged {
return nil, false
}
if e.p.CompareAndSwap(p, i) {
return p, true
}
}
}
tryLoadOrStore
可以像trySwap
一样基于其逻辑来实现,但它不是.我的问题是:既然它们的逻辑相似,为什么它们不以相同的方式实现?
当我试图理解时,我认为这是因为参数类型的不同,如果I
是*any
,它不需要做复制,因为它已经是一个指针,我们不需要关心转义分析.但似乎没有从外部呼叫者那里获取地址的特殊原因.
if e, ok := read.m[key]; ok {
if v, ok := e.trySwap(&value); ok {
if v == nil {
return nil, false
}
return *v, true
}
}
那么我就不知道为什么这两个功能(和其他功能)以不同的方式实现.