结构体切片与结构体指针切片

问题描述 投票:0回答:4

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

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

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

[]MyStruct

假设我在那里有大约一百万个元素,并且我正在大量地处理切片:

  • 我经常添加新元素。 (元素总数未知。)
  • 我时不时地整理一下。
  • 我也删除元素(尽管不如添加新元素那么多)。
  • 我经常读取元素并将它们传递(作为函数参数)。
  • 元素本身的内容不会改变。

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

[]*MyStruct

现在结构体保留在原来的位置,我们只处理指针,我认为这些指针占用的空间较小,因此会使我的操作更快。但现在我给了垃圾收集器更多的工作。

  • 您能否提供何时直接使用结构体以及何时使用结构体指针的一般准则?
  • 我应该担心留给 GC 多少工作吗?
  • 复制结构体与复制指针的性能开销可以忽略不计吗?
  • 也许一百万个元素并不算多。当切片变得更大时(当然仍然适合 RAM),所有这些会发生什么变化?
performance go slice
4个回答
68
投票

我自己也对此感到好奇。运行一些基准测试:

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() 的开销。附加结构下降了 1000 纳秒,附加指针根本没有改变。


12
投票

您能否提供何时直接使用结构体以及何时使用结构体指针的一般准则?

不,这很大程度上取决于您已经提到的所有其他因素。

唯一真正的答案是:进行基准测试并查看。每个案例都是不同的,当你有实际的时间安排时,世界上所有的理论都没有什么区别。

(也就是说,我的直觉是使用指针,并且可能使用

sync.Pool
来帮助垃圾收集器:http://golang.org/pkg/sync/#Pool


3
投票

与映射、切片、通道、函数和方法不同,结构变量通过复制传递,这意味着在幕后分配了更多内存。另一方面,减少指针会减少垃圾收集器的工作量。从我的角度来看,我会更多地考虑三件事:结构复杂性、要处理的数据量以及创建 var 后的功能需求(当它被传递到函数时是否需要可变?等等..)


0
投票

输入 roominfo 结构体 { ID 整数 输入字符串 状态布尔值 床数 int 价格 int } 函数 main() {

房间 := []房间信息{}

rooms = append(rooms, roominfo{ID: 121, Type: "Single", Status: false, BedCount: 1, Price: 100})
rooms = append(rooms, roominfo{ID: 222, Type: "Single", Status: false, BedCount: 1, Price: 120})
rooms = append(rooms, roominfo{ID: 334, Type: "Single", Status: false, BedCount: 1, Price: 150})
rooms = append(rooms, roominfo{ID: 4454, Type: "Double", Status: false, BedCount: 2, Price: 200})

}

© www.soinside.com 2019 - 2024. All rights reserved.