https://mp.weixin.qq.com/s/LIdlk0p32iW2KDjGHGflMQ
这最后怎么得出的 r+0 更快的?什么道理....面试时会被问到吗
1
KaynW 322 天前
谁问你这个给他两个大逼斗
|
2
token10086 322 天前
茴字有几种写法?
|
3
hollc 322 天前
这种性能差异我觉得其实体现出的是底层实现的 bug ,毫无意义的代码反而效率更高
|
4
hxtheone 322 天前 via iPhone
普通开发者了解 go 编译器里寄存器的使用就可以了, 学会文中这点对日常开发没什么太大帮助, 赞同文章的最后一句话, 这些细节差异应该是编译器处理没必要暴露给开发者
|
5
wangritian 322 天前
面试问这种问题就不是想招好好干活的
看上去是多了+0 之后,触发了编译器某个优化逻辑,让上面循环过程中使用的变量停留在寄存器,而不用写回内存再读出来,确实是编译器内部问题,开发者不用管 |
6
rrfeng 322 天前 via Android
开头直接猜编译器优化问题,
看到开始汇编了,以为最后会解释,结果没有?? 那这是狗屁文章。。。 |
7
rrfeng 322 天前 1
无责任猜测:
在 g 里传给 chan 的是 (r+0) 是一个「临时」值,r 没有被传递,因此 r 被优化放到了寄存器上。 而在 f 里要传给 chan 的是变量 r ,所以它不能被优化到寄存器里,只能放到栈上。 所以是寄存器优先原则的作用。 |
8
rrfeng 322 天前
补充一点:文章引用 2 里介绍了 Go 函数参数都是「栈传递」,所以上述解释应该正确
|
9
lxdlam 322 天前
一方面我同意 #3 ,更像是编译器的 bug ,另一方面我本地似乎复现不了这个差距如此巨大的结果,估计可以看下 1.21rc 到现在( go 1.21.6 ) 的差异。
而对于一定程度上的差异( 100000ns per op ),单纯从生成代码上来看,f 生成的函数直接对 r 做了修改,所以需要一次对 r 的 load ,而 g 是对一个临时变量做修改,虽然二者都是一次 load 跟一次 store ,但是 r 毕竟不好说分配在哪儿(也许在 heap 上,也许在 register ,看编译器优化),那么 r 确实可能比起临时变量( go 倾向于分配在 register 上)的读写要更慢。至于为什么会有如此差异,实际上应该是因为编译器识别出来了这个累加 pattern ,而在 f 里因为没有额外操作,所以直接对 r 进行操作,把加数这些都当 immediate value 优化成单次 INCQ 了;而在 g 中,由于又读到了 r + 0 ,编译器首先优化成了将其写入中间变量的操作,又在后续 pass 中发现其实对 r 基本无操作,去掉了这里面所有 r 的主动 reference ,将其完全优化到了完全只读写中间变量,所以生成了这个样子的代码。 以上仅抛砖引玉,我不是 plan9 和 go compiler 专家,只能看个大概,这里面同样可能会有很多说不清的其他因素影响。但是我仍然同意,这种 case 应该 report 给官方去修改,而不是当新时代的语言律师模拟考题,同样,如果在乎这个粒度的性能差距,可能我们会选择更精细的语言和优化方式了,而不是在这继续抄写茴字剩下的写法。 |
10
rrfeng 322 天前 via Android
|
11
pkoukk 322 天前
同意楼上,这应该是编译器可以优化的问题,不应该作为一个 feature 存在
谁面试问这种问题,就给他两个大逼斗 |
12
bybyte 322 天前
语言层面上这两者完全是等价的吧,底层差异这么大那就是编译器的问题了
|
13
mainjzb 322 天前
这样的编译几乎和 g 一样,应该是堆栈导致,go 的编译器确实垃圾。。对比 rust/C/C++
func g2(n int, c chan<- int) { r := 0 for i := 0; i < n; i++ { r += 1 } tmp := r c <- tmp } |
14
mainjzb 322 天前
进一步信息,这个问题只出现在 1.21 和 1.20 中,其他版本编译没有问题。
根据 https://go.godbolt.org/ 提供的反编译信息 |
15
bv 322 天前
你们上来就争论,却不跑一遍作者的示例代码。
Linux Ubuntu i5-8500 测试结果是: go1.21.6 下确实如那篇文章所说 g 明显比 f 快。 go1.22rc2 下 g 和 f 效率几乎无差异。 |
16
Kumo31 322 天前
go compiler 的编译优化确实一言难尽,之前测试过,很基础的循环展开都不会做,官方美名其曰「保证编译速度」: https://github.com/golang/go/issues/51302
|
17
seekseat OP 学到了,蟹蟹大佬们
|