为了账号安全,请及时绑定邮箱和手机立即绑定

Go 编译器是否足够聪明以进行微优化?

Go 编译器是否足够聪明以进行微优化?

Go
饮歌长啸 2021-10-04 15:31:43
我很好奇使用像这样的微优化是否有意义a / 2与a >> 1当 a 是整数时a * 2 对比 a << 1a % 2 对比 a & 1还有一些像这样的我知道任何体面的 C 编译器都足以处理这个问题。另外请不要写过早的优化,因为这些技术太明显了,它甚至不是优化,更像是如何编写代码的偏好问题。PS我尝试做基准测试,时间上的差异在统计上并不显着。我不知道如何检查 go 的字节码,所以谢谢你指出它。
查看完整描述

1 回答

?
斯蒂芬大帝

TA贡献1827条经验 获得超8个赞

简短的回答,是的,编译器优化了这些。但它对intvs uint(大概是任何有符号和无符号整数类型,例如byte)的表现略有不同。


在这两种情况下都避免了乘法和除法指令,但它只是无符号整数的单个指令(以及有符号整数的少量指令)。那是因为您的语句对仅对无符号整数完全等效,而对有符号整数不完全等效。


更长的答案:


采取一个简单的程序,如:


package main


func main() {}


func div2(a int) {

        b := a / 2

        c := a >> 1

        _, _ = b, c

}


func mul2(a int) {

        b := a * 2

        c := a << 1

        _, _ = b, c

}


func mod2(a int) {

        b := a % 2

        c := a & 1

        _, _ = b, c

}

并运行go build -gcflags="-S"将为您提供汇编输出,例如:


"".mod2 t=1 size=32 value=0 args=0x8 locals=0x0

        0x0000 00000 (…/opt.go:17)       TEXT    "".mod2+0(SB),4,$0-8

        …

        0x0000 00000 (…/opt.go:17)       MOVQ    "".a+8(FP),BX

        …

        0x0005 00005 (…/opt.go:18)       MOVQ    BX,AX

        0x0008 00008 (…/opt.go:18)       SARQ    $63,AX

        0x000c 00012 (…/opt.go:18)       MOVQ    BX,DX

        0x000f 00015 (…/opt.go:18)       SUBQ    AX,DX

        0x0012 00018 (…/opt.go:18)       ANDQ    $1,DX

        0x0016 00022 (…/opt.go:18)       ADDQ    AX,DX

        0x0019 00025 (…/opt.go:19)       ANDQ    $1,BX

        0x001d 00029 (…/opt.go:21)       RET     ,

这BX是参数 andDX和BX似乎是两个结果(BX作为结果之一重用)。这里它们略有不同,但只有几条指令(查看显示的源代码行号)并且没有任何除法或乘法指令(所以基本上一样快)。差异是由于算法与逻辑转换以及 Go 如何对负值进行 mod 。


您可以通过在程序中更改int为来确认这一点uint,然后输出包含以下内容:


        0x0008 00008 (…/opt.go:18)       ANDQ    $1,CX

        0x000c 00012 (…/opt.go:19)       ANDQ    $1,BX

即完全相同的指令。对于您给出的每个示例都是如此。


查看完整回答
反对 回复 2021-10-04
  • 1 回答
  • 0 关注
  • 189 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信