首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么我的基准测试在按值与索引的范围上表现出相同的快速性能?

为什么我的基准测试在按值与索引的范围上表现出相同的快速性能?
EN

Stack Overflow用户
提问于 2022-03-17 05:01:22
回答 1查看 51关注 0票数 0
代码语言:javascript
运行
复制
type Item struct {
    A int
    B [1024]byte
}
 
func BenchmarkRange1(b *testing.B) {
    s := make([]Item, 1024)
    for i := 0; i < b.N; i++ {
        for _, v := range s {
            _ = v.A
        }
    }
}
 
func BenchmarkRange2(b *testing.B) {
    s := make([]Item, 1024)
    for i := 0; i < b.N; i++ {
        for i := range s {
            _ = s[i].A
        }
    }
}

现在来看一下基准测试的结果。

代码语言:javascript
运行
复制
go test -bench=BenchmarkRange -benchmem main/copy
goos: darwin
goarch: amd64
pkg: main/copy
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkRange1-12       4577601               260.9 ns/op             0 B/op          0 allocs/op
BenchmarkRange2-12       4697178               254.9 ns/op             0 B/op          0 allocs/op
PASS
ok      main/copy       3.391s

当范围按值切片时,不是要复制元素吗?为什么表演是一样的?当我们按值调整切片时,编译器会做什么优化?

当我通过编译选项“-gc频标=-N”优化编译器时,我将得到预期的结果:

代码语言:javascript
运行
复制
go test -bench=BenchmarkRange -benchmem -gcflags=-N main/copy
goos: darwin
goarch: amd64
pkg: main/copy
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkRange1-12         39004             29481 ns/op              27 B/op          0 allocs/op
BenchmarkRange2-12        777356              1572 ns/op               1 B/op          0 allocs/op
PASS
ok      main/copy       3.169s

谁能解释编译器是如何优化的。

EN

回答 1

Stack Overflow用户

发布于 2022-03-18 19:20:11

使用默认的优化,BenchmarkRange1BenchmarkRange2中的内环将被编译成一个空循环,循环有1024次迭代,就好像您编写了内环一样:

代码语言:javascript
运行
复制
    for i := 0; i < 1024; i++ {

    }

在这两个示例中,编译器都足够聪明地认识到您没有在内部循环中执行任何操作(也就是说,没有使用vv.As[i]s[i].A)。

go.godbolt.org是查看Go编译器生成的程序集的一个很好的资源。例如,BenchmarkRange1中的内循环被编译成以下内容(将AX归零,然后循环1024次):

代码语言:javascript
运行
复制
        XORL    AX, AX
Range1_pc39:
        INCQ    AX
        CMPQ    AX, $1024
        JLT     Range1_pc39

您可以在这里查看完整的输出,以及(通常)解释不同程序集说明的便捷工具提示:https://go.godbolt.org/z/raTPjTrYG

(为了缩短示例,我删除了测试包;//go:nosplit注释并不是真正需要的,但稍微简化了生成的程序集)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71507307

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档