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

我很好奇使用像这样的微优化是否有意义

  • a / 2a >> 1当 a 是整数时

  • a * 2 对比 a << 1

  • a % 2 对比 a & 1

  • 还有一些像这样的

我知道任何体面的 C 编译器都足以处理这个问题。另外请不要写过早的优化,因为这些技术太明显了,它甚至不是优化,更像是如何编写代码的偏好问题。

PS我尝试做基准测试,时间上的差异在统计上并不显着。我不知道如何检查 go 的字节码,所以谢谢你指出它。


饮歌长啸
浏览 190回答 1
1回答

斯蒂芬大帝

简短的回答,是的,编译器优化了这些。但它对intvs uint(大概是任何有符号和无符号整数类型,例如byte)的表现略有不同。在这两种情况下都避免了乘法和除法指令,但它只是无符号整数的单个指令(以及有符号整数的少量指令)。那是因为您的语句对仅对无符号整数完全等效,而对有符号整数不完全等效。更长的答案:采取一个简单的程序,如:package mainfunc main() {}func div2(a int) {&nbsp; &nbsp; &nbsp; &nbsp; b := a / 2&nbsp; &nbsp; &nbsp; &nbsp; c := a >> 1&nbsp; &nbsp; &nbsp; &nbsp; _, _ = b, c}func mul2(a int) {&nbsp; &nbsp; &nbsp; &nbsp; b := a * 2&nbsp; &nbsp; &nbsp; &nbsp; c := a << 1&nbsp; &nbsp; &nbsp; &nbsp; _, _ = b, c}func mod2(a int) {&nbsp; &nbsp; &nbsp; &nbsp; b := a % 2&nbsp; &nbsp; &nbsp; &nbsp; c := a & 1&nbsp; &nbsp; &nbsp; &nbsp; _, _ = b, c}并运行go build -gcflags="-S"将为您提供汇编输出,例如:"".mod2 t=1 size=32 value=0 args=0x8 locals=0x0&nbsp; &nbsp; &nbsp; &nbsp; 0x0000 00000 (…/opt.go:17)&nbsp; &nbsp; &nbsp; &nbsp;TEXT&nbsp; &nbsp; "".mod2+0(SB),4,$0-8&nbsp; &nbsp; &nbsp; &nbsp; …&nbsp; &nbsp; &nbsp; &nbsp; 0x0000 00000 (…/opt.go:17)&nbsp; &nbsp; &nbsp; &nbsp;MOVQ&nbsp; &nbsp; "".a+8(FP),BX&nbsp; &nbsp; &nbsp; &nbsp; …&nbsp; &nbsp; &nbsp; &nbsp; 0x0005 00005 (…/opt.go:18)&nbsp; &nbsp; &nbsp; &nbsp;MOVQ&nbsp; &nbsp; BX,AX&nbsp; &nbsp; &nbsp; &nbsp; 0x0008 00008 (…/opt.go:18)&nbsp; &nbsp; &nbsp; &nbsp;SARQ&nbsp; &nbsp; $63,AX&nbsp; &nbsp; &nbsp; &nbsp; 0x000c 00012 (…/opt.go:18)&nbsp; &nbsp; &nbsp; &nbsp;MOVQ&nbsp; &nbsp; BX,DX&nbsp; &nbsp; &nbsp; &nbsp; 0x000f 00015 (…/opt.go:18)&nbsp; &nbsp; &nbsp; &nbsp;SUBQ&nbsp; &nbsp; AX,DX&nbsp; &nbsp; &nbsp; &nbsp; 0x0012 00018 (…/opt.go:18)&nbsp; &nbsp; &nbsp; &nbsp;ANDQ&nbsp; &nbsp; $1,DX&nbsp; &nbsp; &nbsp; &nbsp; 0x0016 00022 (…/opt.go:18)&nbsp; &nbsp; &nbsp; &nbsp;ADDQ&nbsp; &nbsp; AX,DX&nbsp; &nbsp; &nbsp; &nbsp; 0x0019 00025 (…/opt.go:19)&nbsp; &nbsp; &nbsp; &nbsp;ANDQ&nbsp; &nbsp; $1,BX&nbsp; &nbsp; &nbsp; &nbsp; 0x001d 00029 (…/opt.go:21)&nbsp; &nbsp; &nbsp; &nbsp;RET&nbsp; &nbsp; &nbsp;,这BX是参数 andDX和BX似乎是两个结果(BX作为结果之一重用)。这里它们略有不同,但只有几条指令(查看显示的源代码行号)并且没有任何除法或乘法指令(所以基本上一样快)。差异是由于算法与逻辑转换以及 Go 如何对负值进行 mod 。您可以通过在程序中更改int为来确认这一点uint,然后输出包含以下内容:&nbsp; &nbsp; &nbsp; &nbsp; 0x0008 00008 (…/opt.go:18)&nbsp; &nbsp; &nbsp; &nbsp;ANDQ&nbsp; &nbsp; $1,CX&nbsp; &nbsp; &nbsp; &nbsp; 0x000c 00012 (…/opt.go:19)&nbsp; &nbsp; &nbsp; &nbsp;ANDQ&nbsp; &nbsp; $1,BX即完全相同的指令。对于您给出的每个示例都是如此。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go