java - 对于循环性能: counters with same value vs.不同的值

标签 java for-loop optimization 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
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];
    }
}
环境:
  • MacOS,尝试使用Java8,Java11,Java14
  • 2,4 GHz四核Intel Core i5
  • 最佳答案

    在第一个(更快)版本中,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;
    }
    
    可以不用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;
    }
    
    编译器很可能认识到j是多余的并已将其消除,导致执行的++操作数量减少了一半,占所有算术操作的1/3。这与时间一致:第二个版本每次迭代花费70%的时间。 70%大约是50%,以3:2的比例进行操作时,预期会得到该结果。

    关于java - 对于循环性能: counters with same value vs.不同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63784415/

    相关文章:

    java - 带有外部 JAR 的 Spring Boot 获取 NoClassDefFoundError

    python - 如何在python中的子流程中使用错误处理

    python - 如何在 python 中使用 Gurobi 的 MIPGap 和 TimeLimit?

    java - 如何使用 ArrayList 中的按钮

    java - 如何使用 EMMA 代码覆盖更改 Ant 脚本以便它可以找到运行时覆盖数据?

    swift - 是否有可能使多线程代码效率更高? (双循环 O(n^2))

    mysql - 生成两位数不同的唯一代码

    c++ - O2 中导致 undefined symbol 的 gcc 优化标志

    java - Android - WebView向下滚动时刷新

    javascript - mySQL查询在相同条件下检索数据不同