Go 高性能之结构体切片

概述 #

业务开发中,一个常见的场景是将多个相同类型的 结构体 变量存入一个数据容器中,通常我们会使用 切片 作为数据容器。 那么对于结构体来说,存储其值和存储其指针,性能差异有多大呢?

切片元素为结构体 #

测试代码如下:

package performance

import (
	"strconv"
	"testing"
)

type person struct {
	name string
	age  int
}

func Benchmark_PointerWithValue(b *testing.B) {
	b.StopTimer()

	// 初始化数据
	persons := make([]person, 10000)
	for i := range persons {
		persons[i] = person{
			name: strconv.Itoa(i),
			age:  i,
		}
	}

	b.StartTimer()

	for n := 0; n < b.N; n++ {
		// 切片存储结构体的值
		clonedPersons := make([]person, 10000)
		for i := range persons {
			clonedPersons[i] = persons[i]
		}
	}
}

运行测试,并将基准测试结果写入文件:

# 运行 10000 次, 统计内存分配
$ go test -run='^$' -bench='Benchmark_PointerWithValue' -count=1 -benchtime=10000x -benchmem > value.txt 

切片元素为结构体指针 #

测试代码如下:

package performance

import (
	"strconv"
	"testing"
)

type person struct {
	name string
	age  int
}

func Benchmark_PointerWithValue(b *testing.B) {
	b.StopTimer()

	// 初始化数据
	persons := make([]person, 10000)
	for i := range persons {
		persons[i] = person{
			name: strconv.Itoa(i),
			age:  i,
		}
	}

	b.StartTimer()

	for n := 0; n < b.N; n++ {
		// 切片存储结构体的指针
		clonedPersons := make([]*person, 10000)
		for i := range persons {
			clonedPersons[i] = &(persons[i])
		}
	}
}

运行测试,并将基准测试结果写入文件:

# 运行 10000 次, 统计内存分配
$ go test -run='^$' -bench='Benchmark_PointerWithValue' -count=1 -benchtime=10000x -benchmem > pointer.txt

使用 benchstat 比较差异 #

$ benchstat -alpha=100 pointer.txt value.txt 

# 输出如下
name                 old time/op    new time/op    delta
_PointerWithValue-8    34.6µs ± 0%    65.2µs ± 0%   +88.38%  (p=1.000 n=1+1)    

name                 old alloc/op   new alloc/op   delta
_PointerWithValue-8    81.9kB ± 0%   245.8kB ± 0%  +200.00%  (p=1.000 n=1+1)    

name                 old allocs/op  new allocs/op  delta
_PointerWithValue-8      1.00 ± 0%      1.00 ± 0%      ~     (all equal)

输出的结果分为了三行,分别对应基准期间的: 运行时间、内存分配总量、内存分配次数,相对于 结构体值 类型,采用了 结构体指针 类型后:

  • 运行时间提升了将近 1 倍
  • 内存分配总量减少了 2 倍

感兴趣的读者可以调整 benchtime 参数大小,观察一下性能的变化趋势。

小结 #

当需要将多个相同类型的 结构体 变量存入一个 切片 时,请存储 结构体 变量的 指针

转载申请

本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。

© 蛮荆 | 陕公网安备 61011302001681 号 | 陕ICP备2023004378号-1 | Rendered by Hugo