7.struct使用指针传递

1.问题2.性能分析3.结论1.问题

调用一个函数,如果入参是一个 struct,我们应该使用值传递还是指针传递呢?

2.性能分析

假设有一个 student struct,记录一个学生的基本信息。

type student struct {

id int

name string

sex byte

age int

addr string

}

假设有两个函数分别采用值传递和指针传递。

func PassByValue(s student) {

// Nothing to do.

}

func PassByPtr(s student) {

// Nothing to do.

}

然后写两个基准测试环境,放到 _test.go 结尾的测试文件中。

func BenchmarkPassByVal(b *testing.B) {

var s student

for i := 0; i < b.N; i++ {

PassByVal(s)

}

}

func BenchmarkPassByPtr(b *testing.B) {

var s student

for i := 0; i < b.N; i++ {

PassByPtr(&s)

}

}

假设将上面的代码放到 pass 目录下。下面我们执行基准测试命令,看下使用值传递和指针传递的性能差别。

go test -bench=^BenchmarkPass -benchmem -gcflags="-l" main/pass

goos: windows

goarch: amd64

pkg: main/pass

cpu: 11th Gen Intel(R) Core(TM) i5-11500 @ 2.70GHz

BenchmarkPassByVal-12 873122876 1.333 ns/op 0 B/op 0 allocs/op

BenchmarkPassByPtr-12 1000000000 0.6241 ns/op 0 B/op 0 allocs/op

PASS

ok main/pass 2.215s

-bench=^BenchmarkPass 指定要测试的基准函数名称以 BenchmarkPass 开头。-benchmem 打印基准测试的内存分配统计信息。-gcflags="-l" 表示禁止编译器的内联优化。

可见,当使用值传递 struct,因为发生拷贝的情况,所以性能比指针传递要低。

可以预见的是,随着 struct 大小增加,值传递和指针传递的性能差距会越来越大。

比如在上面的 student 中加入一个长度为 1024 字符的数组。

type student struct {

id int

name string

sex byte

age int

addr string

selfEvaluation [1024]rune

}

再次看下一下值传递和指针传递的性能差距。

go test -bench=^BenchmarkPass -benchmem -gcflags="-l" main/pass

goos: windows

goarch: amd64

pkg: main/pass

cpu: 11th Gen Intel(R) Core(TM) i5-11500 @ 2.70GHz

BenchmarkPassByVal-12 46635990 24.18 ns/op 0 B/op 0 allocs/op

BenchmarkPassByPtr-12 1000000000 0.6894 ns/op 0 B/op 0 allocs/op

PASS

ok main/pass 2.151s

可见,随着 struct 大小增加,值传递和指针传递的性能差距会越来越大。

3.结论

在 Golang 中,struct 可以使用值传递或指针传递进行传递。使用值传递时,函数会创建一个 struct 值的副本,并将该副本传递给函数。使用指针传递时,函数会传递 struct 值的指针。

使用指针传递 struct 通常比使用值传递更有效率,因为在值传递时需要将整个 struct 复制一份,并将其传递给函数。这可能会导致内存使用量增加,并且如果 struct 很大,可能会导致性能下降。

如果你需要在函数中修改 struct 的值,则必须使用指针传递。这是因为使用值传递传递 struct 副本时,对副本的任何更改都不会影响原始 struct。

如果你不需要在函数中修改 struct 的值,基于性能的考虑,建议使用指针传递。如果 struct 大小不大于指针的大小(如在 64 位系统上的 8 字节),那么就用值传递。

以上结论不仅仅适用于 struct,对于所有的大类型(如数组等),在选择值传递还是指针传递时,都应该考虑值拷贝带来的性能开销。

powered by Gitbook该文章修订时间:

2024-08-04 07:27:05