按值或引用存储 net.Conn?
Store net.Conn by value or reference?
我的应用程序使用 sync.Map
来存储通过多个 goroutines 同时访问的开放套接字连接。
我想知道是将这些连接存储为结构 net.Conn
还是作为引用 *net.Conn
。
这两个选项的 benefits/drawbacks 是什么?首选解决方案是什么?
虽然@blackgreen 是正确的,但我会扩展一下推理。
sync.Map
类型明确定义为在 interface{}
上运行。
现在请记住,在 Go 中,接口不仅仅是类型系统使用的抽象;相反,你可以拥有接口类型的值,这些值在内存中的表示是一个 struct
包含两个指针——指向描述存储在变量中的值的动态类型的内部对象,以及指向值本身(或运行时在堆上创建的副本)。
这意味着,如果您要在 sync.Map
中存储指向任何内容的指针,则任何此类存储的指针都将被转换为 interface{}
类型的值,并且它将占据完全相同的 space 在 sync.Map
.
相反,如果您将 net.Conn
类型的值直接存储在那里,它们将被直接存储——仅仅因为它们已经是接口值,所以 Go 将只复制这对指针。
从表面上看,就使用的 space 而言,这两种方法似乎不相上下,但请耐心等待。
要在 sync.Map
等容器数据类型中存储指向 net.Conn
值的指针,程序必须确保该值分配在堆上(而不是直接分配在容器的堆栈上)当前 运行 goroutine),这一事实可能会迫使编译器安排确保原始 net.Conn
值直接分配在堆上。
换句话说,存储指向接口类型变量的指针在内存使用方面可能(并且通常会——由于典型代码的组织方式)更加浪费。
此外,大多数取消引用(指针追逐)往往会破坏 CPU 缓存;这不会改变游戏规则,但当您在紧密循环中迭代集合时,可能会增加几微秒。
话虽如此,我建议不要完全放弃在 sync.Map
等容器中存储指针:偶尔它会派上用场——例如,要为切片重用数组,通常将指针存储到第一个此类数组的元素。
我的应用程序使用 sync.Map
来存储通过多个 goroutines 同时访问的开放套接字连接。
我想知道是将这些连接存储为结构 net.Conn
还是作为引用 *net.Conn
。
这两个选项的 benefits/drawbacks 是什么?首选解决方案是什么?
虽然@blackgreen 是正确的,但我会扩展一下推理。
sync.Map
类型明确定义为在 interface{}
上运行。
现在请记住,在 Go 中,接口不仅仅是类型系统使用的抽象;相反,你可以拥有接口类型的值,这些值在内存中的表示是一个 struct
包含两个指针——指向描述存储在变量中的值的动态类型的内部对象,以及指向值本身(或运行时在堆上创建的副本)。
这意味着,如果您要在 sync.Map
中存储指向任何内容的指针,则任何此类存储的指针都将被转换为 interface{}
类型的值,并且它将占据完全相同的 space 在 sync.Map
.
相反,如果您将 net.Conn
类型的值直接存储在那里,它们将被直接存储——仅仅因为它们已经是接口值,所以 Go 将只复制这对指针。
从表面上看,就使用的 space 而言,这两种方法似乎不相上下,但请耐心等待。
要在 sync.Map
等容器数据类型中存储指向 net.Conn
值的指针,程序必须确保该值分配在堆上(而不是直接分配在容器的堆栈上)当前 运行 goroutine),这一事实可能会迫使编译器安排确保原始 net.Conn
值直接分配在堆上。
换句话说,存储指向接口类型变量的指针在内存使用方面可能(并且通常会——由于典型代码的组织方式)更加浪费。
此外,大多数取消引用(指针追逐)往往会破坏 CPU 缓存;这不会改变游戏规则,但当您在紧密循环中迭代集合时,可能会增加几微秒。
话虽如此,我建议不要完全放弃在 sync.Map
等容器中存储指针:偶尔它会派上用场——例如,要为切片重用数组,通常将指针存储到第一个此类数组的元素。