脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Golang - Golang数据结构性能优化实践

Golang数据结构性能优化实践

2024-01-02 14:27DeepNoMind Golang

如果你有Golang开发经验,一定定义过struct类型。 但可能你不知道,通过简单的重新排序struct字段,可以极大提高Go程序的速度和内存使用效率! 是不是难以置信?我们一起来看一下吧! 简单Demo type BadStruct struct { age uint8 passportNu

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

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

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

Golang数据结构性能优化实践

简单Demo

type BadStruct struct {
 age         uint8
 passportNum uint64
 siblings    uint16
}

type GoodStruct struct {
 age         uint8
 siblings    uint16
 passportNum uint64
}

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

// Output
Bad struct is 24 bytes long
Good struct is 16 bytes long

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

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

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

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

数据结构对齐

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

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

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

Golang数据结构性能优化实践

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

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

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

非常低效。

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

Golang数据结构性能优化实践

4字节数据只能从内存地址0或4开始

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

Golang数据结构性能优化实践

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

数据结构填充

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

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

这就是额外内存的来源!

我们来回顾一下BadStruct和GoodStruct。

Golang数据结构性能优化实践

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()
 }
}

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

Golang数据结构性能优化实践

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

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

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

结语

好了,全文到此为止,我们以一个简单的行动呼吁来结束:一定要对struct结构字段进行重排序!

原文地址:https://mp.weixin.qq.com/s?__biz=MzU2MTgxODgwNA==&mid=2247487623&idx=1&sn=f331bddca7203403723225cb04d1a2e5

延伸 · 阅读

精彩推荐
  • Golangjenkins构建go及java项目的方法

    jenkins构建go及java项目的方法

    这篇文章主要介绍了jenkins构建go及java项目,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值了,需要的朋友...

    funnyZpC8272021-04-23
  • Golang解析golang中的并发安全和锁问题

    解析golang中的并发安全和锁问题

    本文我们来学习一下golang中的并发安全和锁问题,文章通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参...

    专职10272021-11-30
  • Golanggo等待一组协程结束的操作方式

    go等待一组协程结束的操作方式

    这篇文章主要介绍了go等待一组协程结束的操作方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    cj_2866272021-06-15
  • Golang详解golang consul-grpc 服务注册与发现

    详解golang consul-grpc 服务注册与发现

    这篇文章主要介绍了详解golang consul-grpc 服务注册与发现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    hatlonely5192020-05-16
  • Golanggo语言实现银行卡号Luhn校验

    go语言实现银行卡号Luhn校验

    这篇文章主要为大家介绍了go语言Luhn校验测试银行卡号码的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    dz456937722022-10-09
  • Golang基于Golang开发一个轻量级登录库/框架

    基于Golang开发一个轻量级登录库/框架

    几乎每个项目都会有登录,退出等用户功能,而登录又不单仅仅是登录,我们要考虑很多东西。所以本文就来用Golang开发一个轻量级登录库/框架吧...

    秋玻5222023-05-07
  • GolangGo 语言 Errgroup 库的使用方式和实现原理

    Go 语言 Errgroup 库的使用方式和实现原理

    本文我们介绍 Go 方法提供的 errgroup 库,该库最近新增了控制并发数量的功能。我们先介绍了三种使用方式,然后通过阅读源码,分析其实现原理。...

    Golang语言开发栈3542022-10-24
  • Golanggolang 字符串切片去重实例

    golang 字符串切片去重实例

    这篇文章主要介绍了golang 字符串切片去重实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    天天water7912021-03-15