Sta*_*sev 9 java optimization for-loop micro-optimization
我有一个带有 2 个计数器的循环:i 和 j。如果它们具有相同的值 - 迭代的工作速度比它们的值不同时快得多:
Benchmark Mode Cnt Score Error Units
FloatsArrayBenchmark.times thrpt 20 341805.800 ± 1623.320 ops/s
FloatsArrayBenchmark.times2 thrpt 20 198764.909 ± 1608.387 ops/s
Run Code Online (Sandbox Code Playgroud)
Java 字节码是相同的,这意味着它与一些较低级别的优化有关。有人可以解释为什么会这样吗?这是基准:
import org.openjdk.jmh.annotations.*;
public class FloatsArrayBenchmark {
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(new String[]{FloatsArrayBenchmark.class.getSimpleName()});
}
@Benchmark @Fork(value = 1, warmups = 0)
public void times(Data data) {
float[] result = new float[10000];;
for (int i = 0, j=0; i < 9_999; i++,j++)
result[j] = data.floats[i] * 10;
}
@Benchmark @Fork(value = 1, warmups = 0)
public void times2(Data data) {
float[] result = new float[10000];
for (int i = 0,j=1; i < 9_999; i++,j++)
result[j] = data.floats[i] * 10;
}
@State(Scope.Benchmark)
public static class Data {
private final float[] floats = new float[10000];
}
}
Run Code Online (Sandbox Code Playgroud)
环境:
在第一个(更快)版本中,i总是(有效)与 具有相同的值j,因此:
public void times(Data data) {
float[] result = new float[10000];;
for (int i=0, j=0; i < 9_999; i++,j++)
result[j] = data.floats[i] * 10;
}
Run Code Online (Sandbox Code Playgroud)
可以重写而不会j产生相同的效果:
public void times(Data data) {
float[] result = new float[10000];;
for (int i = 0; i < 9_999; i++)
result[i] = data.floats[i] * 10;
}
Run Code Online (Sandbox Code Playgroud)
编译器很可能认识到这j是多余的并消除了它,导致++执行的运算数量减少了一半,占所有算术运算的 1/3。这与时间是一致的:第二个版本每次迭代花费的时间延长了 70%。70% 大约为 50%,是 3:2 操作比例的预期结果。