附加到 slice 糟糕的性能.. 为什么?
Appending to slice bad performance.. why?
我目前正在使用 GoLang 创建游戏。我正在测量 FPS。我注意到使用 for 循环附加到切片时会损失 7 fps,如下所示:
vertexInfo := Opengl.OpenGLVertexInfo{}
for i := 0; i < 4; i = i + 1 {
vertexInfo.Translations = append(vertexInfo.Translations, float32(s.x), float32(s.y), 0)
vertexInfo.Rotations = append(vertexInfo.Rotations, 0, 0, 1, s.rot)
vertexInfo.Scales = append(vertexInfo.Scales, s.xS, s.yS, 0)
vertexInfo.Colors = append(vertexInfo.Colors, s.r, s.g, s.b, s.a)
}
我正在为每个精灵、每次抽奖都这样做。问题是,为什么我只循环多次并将相同的东西附加到这些切片中,性能就会受到如此巨大的影响?有没有更有效的方法来做到这一点?这不像我在添加大量数据。每个切片包含大约 16 个元素,如上所示 (4 x 4)。
当我简单地将所有 16 个元素放在一个 []float32{1..16}
中时,fps 提高了大约 4。
更新: 我对每个追加进行了基准测试,似乎每个追加都需要 1 fps 来执行。考虑到这个数据是相当静态的,这似乎很多。我只需要4 次迭代...
更新: 添加了 github 回购 https://github.com/Triangle345/GT
一个空切片是空的。要追加,它必须分配内存。然后你做更多的追加,这必须分配更多的内存。
要加快速度,请使用固定大小的数组或使用 make
创建具有正确长度的切片,或者在声明时使用项目初始化切片。
如果目标切片的容量小于追加后切片的长度,内置函数 append()
需要创建一个新的支持数组。这还需要将目标中的当前元素复制到新分配的数组中,因此开销很大。
您附加到的切片很可能是空切片,因为您使用了切片文字来创建 Opengl.OpenGLVertexInfo
值。尽管 append()
考虑到未来并分配了比附加指定元素所需的更大的数组,但在您的情况下,可能需要多次重新分配才能完成 4 次迭代。
如果您像这样创建和初始化 vertexInfo
,则可以避免重新分配:
vertexInfo := Opengl.OpenGLVertexInfo{
Translations: []float32{float32(s.x), float32(s.y), 0, float32(s.x), float32(s.y), 0, float32(s.x), float32(s.y), 0, float32(s.x), float32(s.y), 0},
Rotations: []float64{0, 0, 1, s.rot, 0, 0, 1, s.rot, 0, 0, 1, s.rot, 0, 0, 1, s.rot},
Scales: []float64{s.xS, s.yS, 0, s.xS, s.yS, 0, s.xS, s.yS, 0, s.xS, s.yS, 0},
Colors: []float64{s.r, s.g, s.b, s.a, s.r, s.g, s.b, s.a, s.r, s.g, s.b, s.a, s.r, s.g, s.b, s.a},
}
另请注意,此结构文字将处理不必在切片后面重新分配数组的问题。但是,如果在代码的其他地方(我们看不到)向这些切片添加更多元素,它们可能会导致重新分配。如果是这种情况,您应该创建容量更大的切片,覆盖 "future" 个分配(例如 make([]float64, 16, 32)
)。
我目前正在使用 GoLang 创建游戏。我正在测量 FPS。我注意到使用 for 循环附加到切片时会损失 7 fps,如下所示:
vertexInfo := Opengl.OpenGLVertexInfo{}
for i := 0; i < 4; i = i + 1 {
vertexInfo.Translations = append(vertexInfo.Translations, float32(s.x), float32(s.y), 0)
vertexInfo.Rotations = append(vertexInfo.Rotations, 0, 0, 1, s.rot)
vertexInfo.Scales = append(vertexInfo.Scales, s.xS, s.yS, 0)
vertexInfo.Colors = append(vertexInfo.Colors, s.r, s.g, s.b, s.a)
}
我正在为每个精灵、每次抽奖都这样做。问题是,为什么我只循环多次并将相同的东西附加到这些切片中,性能就会受到如此巨大的影响?有没有更有效的方法来做到这一点?这不像我在添加大量数据。每个切片包含大约 16 个元素,如上所示 (4 x 4)。
当我简单地将所有 16 个元素放在一个 []float32{1..16}
中时,fps 提高了大约 4。
更新: 我对每个追加进行了基准测试,似乎每个追加都需要 1 fps 来执行。考虑到这个数据是相当静态的,这似乎很多。我只需要4 次迭代...
更新: 添加了 github 回购 https://github.com/Triangle345/GT
一个空切片是空的。要追加,它必须分配内存。然后你做更多的追加,这必须分配更多的内存。
要加快速度,请使用固定大小的数组或使用 make
创建具有正确长度的切片,或者在声明时使用项目初始化切片。
如果目标切片的容量小于追加后切片的长度,内置函数 append()
需要创建一个新的支持数组。这还需要将目标中的当前元素复制到新分配的数组中,因此开销很大。
您附加到的切片很可能是空切片,因为您使用了切片文字来创建 Opengl.OpenGLVertexInfo
值。尽管 append()
考虑到未来并分配了比附加指定元素所需的更大的数组,但在您的情况下,可能需要多次重新分配才能完成 4 次迭代。
如果您像这样创建和初始化 vertexInfo
,则可以避免重新分配:
vertexInfo := Opengl.OpenGLVertexInfo{
Translations: []float32{float32(s.x), float32(s.y), 0, float32(s.x), float32(s.y), 0, float32(s.x), float32(s.y), 0, float32(s.x), float32(s.y), 0},
Rotations: []float64{0, 0, 1, s.rot, 0, 0, 1, s.rot, 0, 0, 1, s.rot, 0, 0, 1, s.rot},
Scales: []float64{s.xS, s.yS, 0, s.xS, s.yS, 0, s.xS, s.yS, 0, s.xS, s.yS, 0},
Colors: []float64{s.r, s.g, s.b, s.a, s.r, s.g, s.b, s.a, s.r, s.g, s.b, s.a, s.r, s.g, s.b, s.a},
}
另请注意,此结构文字将处理不必在切片后面重新分配数组的问题。但是,如果在代码的其他地方(我们看不到)向这些切片添加更多元素,它们可能会导致重新分配。如果是这种情况,您应该创建容量更大的切片,覆盖 "future" 个分配(例如 make([]float64, 16, 32)
)。