Golang数据结构性能优化实践

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

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

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

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

简单Demo

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

type GoodStruct struct {
	age         uint8
	siblings    uint16
	passportNum uint64
}

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

bash 复制代码
// Output
Bad struct is 24 bytes long
Good 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字段重新排序来节省额外的内存!

这种优化为什么重要?

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

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

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

golang 复制代码
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",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!

本文由mdnice多平台发布

相关推荐
喵个咪10 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
夜悊15 小时前
Go网络编程的学习代码示例:客户端/服务端(C/S)模型
go
审判长烧鸡21 小时前
【AI问答】GO代码循环返值
go
捧 花21 小时前
Eino框架记忆功能实现指南
go·agent·eino
Java陈序员1 天前
主流数据库通吃!一款开源实用的数据库备份管理工具!
react.js·postgresql·go
云浪1 天前
搞懂 Go WaitGroup:一篇文章彻底理解并发等待机制
后端·go
喵个咪2 天前
选择第三方IAM还是自建权限体系?中小型后台系统权限架构决策指南
后端·架构·go
喵个咪2 天前
AI重构软件开发范式:框架与脚手架为何仍是生产级开发的刚需?
架构·go·ai编程
夜悊2 天前
Go并发编程的学习代码示例:生产者消费者模型
go
久违 °2 天前
【AI-Agent】TagMatrix 数据标注工具开发
人工智能·数据分析·go·agent·数据隐私