写点什么

Golang 数据结构性能优化实践

作者:俞凡
  • 2023-11-26
    上海
  • 本文字数:1612 字

    阅读完需:约 5 分钟

仅仅通过对 struct 字段重新排序,优化内存对齐方式,就可以获得明显的内存和执行效率提升。原文: How to Speed Up Your Struct in Golang



如果你有 Golang 开发经验,一定定义过 struct 类型。


但可能你不知道,通过简单的重新排序 struct 字段,可以极大提高 Go 程序的速度和内存使用效率!


是不是难以置信?我们一起来看一下吧!

简单 Demo

type BadStruct struct {  age         uint8  passportNum uint64  siblings    uint16}
type GoodStruct struct { age uint8 siblings uint16 passportNum uint64}
复制代码


在上面的代码片段中,我们创建了两个具有相同字段的结构体。然后编写一个简单程序分别输出其内存使用情况。


// OutputBad struct is 24 bytes longGood struct is 16 bytes long
复制代码


如你所见,它们在内存使用方面并不一样。


是什么原因导致两个完全相似的 struct 消耗的内存不同?


答案在于数据在计算机内存中的排列方式。


简而言之,数据结构对齐。

数据结构对齐


CPU 以字(word)为单位读取数据,而不是字节(byte)。


64 位系统中,一个 word 是 8 个字节,而 32 位系统中,一个 word 是 4 个字节。


简而言之,CPU 以其字长的倍数读取内存地址。



想象一下,在 64 位系统中,为了获取变量passportNum,CPU 需要两个周期来访问数据。


第一个周期将获取内存的 0 到 7 字节,下一个周期获取其余内存字节。


把它想象成一个笔记本,每页只能存储一个字大小的数据(在本例中为 8 字节)。如果passportNum分散在两个页,则需要两次读取才能检索到完整的数据。


非常低效。


因此需要数据结构对齐,让计算机将数据存储在等于数据大小倍数的地址上。



例如,2 字节数据可以存储在内存 0、2 或 4 中,而 4 字节数据可以存储在内存 0、4 或 8 中。



通过简单的对齐数据,计算机确保可以在一个 CPU 周期内检索到变量passportNum

数据结构填充


填充是实现数据对齐的关键。


计算机通过在数据结构之间填充额外的字节,从而对齐字段。


这就是额外内存的来源!


我们来回顾一下BadStructGoodStruct



GoodStruct消耗更少的内存,仅仅因为与BadStruct相比,其 struct 字段顺序更合理。


由于填充,两个 13 字节的数据结构分别变成了 16 字节和 24 字节。


因此,可以仅仅通过对 struct 字段重新排序来节省额外的内存!

这种优化为什么重要?

问题来了,你为什么要关心这个?


两个方面,速度和内存使用。


我们做一个简单的基准测试来证明!


func traverseGoodStruct() uint16 {  var arbitraryNum uint16    for _, goodStruct := range GoodStructArr {    arbitraryNum += goodStruct.siblings  }    return arbitraryNum}
func traverseBadStruct() uint16 { var arbitraryNum uint16 for _, badStruct := range BadStructArr { arbitraryNum += badStruct.siblings } return arbitraryNum}
func BenchmarkTraverseGoodStruct(b *testing.B) { for n := 0; n < b.N; n++ { traverseGoodStruct() }}
func BenchmarkTraverseBadStruct(b *testing.B) { for n := 0; n < b.N; n++ { traverseBadStruct() }}
复制代码


GoodStructBadStruct进行基准测试的方法是循环遍历数组,并将 struct 字段累加到变量中。



从结果中可以看出,遍历GoodStruct确实比BadStruct花费时间更少。


对 struct 字段重排序可以优化应用程序的内存使用和速度。


想象一下,维护一个具有大量结构体的大型应用程序,改变将会更为明显。

结语

好了,全文到此为止,我们以一个简单的行动呼吁来结束:


一定要对 struct 结构字段进行重排序!




你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!

发布于: 刚刚阅读数: 4
用户头像

俞凡

关注

公众号:DeepNoMind 2017-10-18 加入

俞凡,Mavenir Systems研发总监,关注高可用架构、高性能服务、5G、人工智能、区块链、DevOps、Agile等。公众号:DeepNoMind

评论

发布
暂无评论
Golang数据结构性能优化实践_golang_俞凡_InfoQ写作社区