小编典典

结构切片与指向结构的指针切片

go

我经常使用结构片。这是此类结构的示例:

type MyStruct struct {
    val1, val2, val3    int
    text1, text2, text3 string
    list                []SomeType
}

所以我定义我的切片如下:

[]MyStruct

假设我有大约一百万个元素,并且我正在大量使用切片:

  • 我经常添加新元素。(元素总数未知。)
  • 我时不时地整理一下。
  • 我还删除了元素(虽然没有添加新元素那么多)。
  • 我经常阅读元素并将它们传递(作为函数参数)。
  • 元素本身的内容不会改变。

我的理解是,这会导致对实际结构的大量改组。另一种方法是创建一个指向结构的指针:

[]*MyStruct

现在结构体保持原样,我们只处理我认为占用空间较小的指针,因此会使我的操作更快。但是现在我给垃圾收集器做更多的工作。

  • 你能提供什么时候直接使用结构体还是什么时候使用指向结构体的指针的一般指南?
  • 我是否应该担心留给 GC 的工作量是多少?
  • 复制结构与复制指针的性能开销可以忽略不计?
  • 也许一百万个元素并不多。当切片变得更大(但仍然适合 RAM,当然)时,所有这些如何变化?

阅读 401

收藏
2021-12-21

共1个答案

小编典典

只是自己对这个很好奇。运行一些基准测试:

type MyStruct struct {
    F1, F2, F3, F4, F5, F6, F7 string
    I1, I2, I3, I4, I5, I6, I7 int64
}

func BenchmarkAppendingStructs(b *testing.B) {
    var s []MyStruct

    for i := 0; i < b.N; i++ {
        s = append(s, MyStruct{})
    }
}

func BenchmarkAppendingPointers(b *testing.B) {
    var s []*MyStruct

    for i := 0; i < b.N; i++ {
        s = append(s, &MyStruct{})
    }
}

结果:

BenchmarkAppendingStructs  1000000        3528 ns/op
BenchmarkAppendingPointers 5000000         246 ns/op

带走:我们以纳秒为单位。对于小切片可能可以忽略不计。但是对于数百万次操作,这就是毫秒和微秒之间的差异。

顺便说一句,我尝试使用预先分配的切片(容量为 1000000)再次运行基准测试,以消除 append() 定期复制底层数组的开销。附加结构下降了 1000ns,附加指针根本没有改变。

2021-12-21