关于 Golang Go语言中 sync.Map 的一点疑问
sync.Map 在删除时如果是 read 中的 key ,那么并不是真实的删除,而是将 entry 中的 p 置换成 nil ,但是 value 直接设置为 nil ,那么怎么区分一个值是被置换成了 nil 还是一开始就设置为 nil 呢?
关于 Golang Go语言中 sync.Map 的一点疑问
sync.Map.Load 方法有两个返回值
更多关于关于 Golang Go语言中 sync.Map 的一点疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
关键在于 Sync.Map.Store(k, v) ,当你传值为 nil 调用 Store 时,因为 k,v 的类型是 any (也就是 interface{}),在 runtime 也就是结构体 iface ,如果你传入的是 nil ,golang 会用 iface 把这个 nil 包一下,对应的 _type 与 data 应该都是空值(nil),所以你可以在 sync.Map.Store 里面后续的源码里可以看到,value 是可以拿到内存地址的(&value ),因为这个 value 本质上是个 iface 结构体,而直接写 &nil 在 Golang 是会编译报错的。
而 readOnly.m 的值类型是 entry ,entry.p 是一个指向 interface{} 值的指针。当你调用 Sync.Map.Store(k, nil) 时,对应的 entry.p 不会变成 nil ,而是变成一个指向 interface{} (iface) 的指针,这个 iface 相当于包装了值 nil 。
而 Sync.Map.Delete() 就确实会把 entry.p 变成 nil ,所以二者确实是有明确区别的。
写一个函数就可以简单验证,也可以汇编拿出来自己看下:
package main
import "fmt"
func printAnyAddr(v any) {
fmt.Println(&v)
}
func main() {
printAnyAddr(nil)
}
这里 iface 写错了,interface{} 应该是对应 eface
func main() {
var a interface{}
fmt.Println(a == nil)
a = (*int)(nil)
fmt.Println(a == nil)
}
上面的答案是 true 和 false
OP 要是弄懂了上面的原因 ,那应该就能弄懂你提的问题
#2 感谢回复,解答得很清晰
关于您在 Golang 中对 sync.Map
的疑问,我很乐意提供一些专业的解答。
sync.Map
是 Go 语言标准库提供的一个并发安全的 map 实现,它适用于读多写少的场景。与传统的 map
相比,sync.Map
通过内部机制减少了锁的使用,从而提高了并发性能。
在使用 sync.Map
时,您可能会遇到以下几个常见操作:
- Store:用于存储键值对。如果键已经存在,则更新其对应的值。
- Load:根据键加载值。如果键存在,则返回对应的值及其是否存在的标志;如果键不存在,则返回 nil 和 false。
- LoadOrStore:如果键存在,则返回其对应的值及其是否存在的标志;如果键不存在,则存储键值对并返回存储的值及 true。
- Delete:根据键删除键值对。
- Range:遍历
sync.Map
中的所有键值对,对每个键值对执行指定的函数。
需要注意的是,sync.Map
不支持像传统 map
那样的索引操作,即不能通过键直接获取值(除非使用 Load
或 LoadOrStore
方法)。此外,由于 sync.Map
的内部实现较为复杂,因此在某些情况下,其性能可能不如使用互斥锁(sync.Mutex
)保护的 map
。
希望这些信息能帮助您更好地理解和使用 sync.Map
。如果您有其他问题或需要更详细的解答,请随时提问。