Golang对struct字段重新排序优化数据结构性能实践

 更新时间:2023年12月15日 11:44:18   作者:俞凡  
这篇文章主要为大家介绍了Golang对struct字段重新排序优化数据结构性能实践,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

通过对 struct 字段重新排序

仅仅通过对 struct 字段重新排序,优化内存对齐方式,就可以获得明显的内存和执行效率提升。

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

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

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

简单 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 以其字长的倍数读取内存地址。

想象一下,在 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 结构字段进行重排序!

以上就是Golang对struct字段重新排序优化数据结构性能实践的详细内容,更多关于Golang struct重新排序的资料请关注脚本之家其它相关文章!

相关文章

  • Go基础教程系列之数据类型详细说明

    Go基础教程系列之数据类型详细说明

    这篇文章主要介绍了Go基础教程系列之数据类型详细说明,需要的朋友可以参考下
    2022-04-04
  • 浅谈Go语言多态的实现与interface使用

    浅谈Go语言多态的实现与interface使用

    如果大家系统的学过C++、Java等语言以及面向对象的话,相信应该对多态不会陌生。多态是面向对象范畴当中经常使用并且非常好用的一个功能,它主要是用在强类型语言当中,像是Python这样的弱类型语言,变量的类型可以随意变化,也没有任何限制,其实区别不是很大
    2021-06-06
  • Go语言中内存泄漏的常见案例与解决方法

    Go语言中内存泄漏的常见案例与解决方法

    Go虽然是自动GC类型的语言,但在编码过程中如果不注意,很容易造成内存泄漏的问题,本文为大家整理了一些内存泄漏的常见Case与解决方法,希望对大家有所帮助
    2024-03-03
  • Go项目中使用Casbin实现RBAC权限管理教程

    Go项目中使用Casbin实现RBAC权限管理教程

    本文主要介绍了Go项目中使用Casbin实现RBAC权限管理教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-01-01
  • Go语言标准输入输出库的基本使用教程

    Go语言标准输入输出库的基本使用教程

    输入输出在任何一门语言中都必须提供的一个功能,下面这篇文章主要给大家介绍了关于Go语言标准输入输出库的基本使用,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-02-02
  • Golang实现请求限流的几种办法(小结)

    Golang实现请求限流的几种办法(小结)

    这篇文章主要介绍了Golang实现请求限流的几种办法(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • 一文详解在Go中如何使用Viper来管理配置

    一文详解在Go中如何使用Viper来管理配置

    Viper 是一个功能齐全的 Go 应用程序配置库,支持很多场景。在本文中,我们将深入探讨 Viper 的各种用法和使用场景,以帮助读者更好地了解和使用 Viper 来管理应用程序配置,感兴趣的同学可以参考阅读
    2023-05-05
  • Go语言七篇入门教程五文件及包

    Go语言七篇入门教程五文件及包

    本章节主要介绍go语言的文件处理与包管理,本文是Go语言七篇入门教程系列篇,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • go 压缩解压zip文件源码示例

    go 压缩解压zip文件源码示例

    这篇文章主要为大家介绍了go压缩及解压zip文件的源码示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • Go语言中的速率限流策略全面详解

    Go语言中的速率限流策略全面详解

    这篇文章主要为大家介绍了Go语言中的速率限流策略全面详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11

最新评论