Performance Go运行时是否在每次迭代中评估for循环条件?
以下是《Go编程语言》一书中的代码片段: t:=0.0时的Performance Go运行时是否在每次迭代中评估for循环条件?,performance,go,compiler-optimization,Performance,Go,Compiler Optimization,以下是《Go编程语言》一书中的代码片段: t:=0.0时的;t
;t
似乎for循环条件
t
中的表达式必须在for循环的每次迭代之前求值。或者,编译器是否通过预先计算表达式的结果(假设在迭代过程中没有任何变量发生变化)来对此进行优化?上述编码风格是否会影响性能?它似乎没有经过优化,也没有列在“”中
如中所述
gc编译器不执行任何循环优化。该编译器的主要目标之一是快速编译。虽然改进的优化总是有用的,但它必须符合这一目标
但这本可以改变的。“”中说明了一种很好的技术,可以查看go程序生成的汇编代码。另请参见最近的2016年“”文章。
和“”也有帮助:请参阅 您可以看到始终计算的“
t
”部分
.L2:
movsd xmm0, QWORD PTR [rbp-24]
addsd xmm0, xmm0
movsd xmm1, QWORD PTR .LC2[rip]
mulsd xmm0, xmm1
ucomisd xmm0, QWORD PTR [rbp-8]
seta al
test al, al
这实际上取决于Go版本,但Go版本go1.7 windows/amd64确实会计算一次该值 Go代码:
var cycles = 10.0
var res = 1000.0
for t := 0.0; t < cycles*2*math.Pi; t += res {
}
f64_404f6a7a2955385e
是一个预先计算的双精度值,等于10*2*math.Pi
或62.8318530718
转到编译器,这样这些优化将不断改进,因为它们从中受益匪浅。目前,SSA仅在amd64上提供:
编译器工具链
此版本包括用于64位x86的新代码生成后端
系统,根据2015年的提案,该提案正在开发中
从那时起新的后端基于SSA,可生成更紧凑、更灵活的
高效的代码,并为优化提供更好的平台,例如
边界检查消除
:
编译器工具链
Go 1.7为64位x86系统引入了新的编译器后端。围棋
1.8,该后端已得到进一步开发,目前已用于所有
架构
当前Go编译器不会将循环不变计算移到循环之外 编译器的过程列表可以在这里看到 在@creker的示例中,编译器执行常量折叠,而不是循环不变的代码运动 作为旁注,几个月前我确实为Go编译器通过了LICM
在通常使用的Go基准上,这并不能极大地提高性能。(我谴责糟糕的寄存器分配:P)这似乎比我的答案更准确+1当前编译器是否与1.7或1.8 beta版本相同2?这是否意味着我的答案比克雷克的更准确?在1.7中?在1.8中仍然是这样吗?是的,适用于所有版本,包括master branch.OK。这似乎证实了我在回答中提到的+1.
var cycles = 10.0
var res = 1000.0
for t := 0.0; t < cycles*2*math.Pi; t += res {
}
movsd [rsp+58h+var_20], xmm0
mov [rsp+58h+var_18], 0
mov [rsp+58h+var_10], 0
lea rax, qword_494500
mov [rsp+58h+var_58], rax
lea rax, [rsp+58h+var_20]
mov [rsp+58h+var_50], rax
mov [rsp+58h+var_48], 0
call runtime_convT2E
mov rax, [rsp+58h+var_40]
mov rcx, [rsp+58h+a] ; a
mov [rsp+58h+var_18], rax
mov [rsp+58h+var_10], rcx
lea rax, [rsp+58h+var_18]
mov [rsp+58h+var_58], rax
mov [rsp+58h+var_50], 1
mov [rsp+58h+var_48], 1
call fmt_Println
movsd xmm0, cs:$f64_408f400000000000
movsd xmm1, [rsp+58h+t]
addsd xmm0, xmm1
movsd [rsp+58h+t], xmm0
movsd xmm1, cs:$f64_404f6a7a2955385e
ucomisd xmm1, xmm0
ja loc_401083