我有以下代码

public class BenchMark {
    public static void main(String args[]) {
        doLinear();

        doLinear();

        doLinear();

        doLinear();

    }


    private static void doParallel() {
        IntStream range = IntStream.range(1, 6).parallel();

        long startTime = System.nanoTime();
        int reduce = range
                .reduce((a, item) -> a * item).getAsInt();
        long endTime = System.nanoTime();
        System.out.println("parallel: " +reduce + " -- Time: " + (endTime - startTime));
    }

    private static void doLinear() {
        IntStream range = IntStream.range(1, 6);

        long startTime = System.nanoTime();
        int reduce = range
                .reduce((a, item) -> a * item).getAsInt();
        long endTime = System.nanoTime();
        System.out.println("linear: " +reduce + " -- Time: " + (endTime - startTime));
    }

}

我试图对流进行基准测试,但是在一次又一次地调用相同的函数时,这个执行时间稳步减少

输出:
linear: 120 -- Time: 57008226
linear: 120 -- Time: 23202
linear: 120 -- Time: 17192
linear: 120 -- Time: 17802

Process finished with exit code 0

第一次和第二次执行时间 之间存在 巨大差异。

我确信 JVM 可能会在幕后做一些技巧,但有人可以帮助我了解那里到底发生了什么吗?

有没有办法避免这种优化,以便我可以对真实的执行时间进行基准测试?

最佳答案


  • 第一次调用的大量延迟是由于完整的 lambda 运行时子系统的初始化。您只需为整个应用程序支付一次。
  • 当您的代码第一次到达任何给定的 lambda 表达式时,您需要为该 lambda 的链接(invokedynamic 调用站点的初始化)付费。
  • 经过一些迭代,由于 JIT 编译器优化了您的缩减代码,您将看到额外的加速。



  • 您在这里提出了一个矛盾:“真正的”执行时间是您在预热后,当所有优化都已应用时获得的时间。这是实际应用程序将体验的运行时。前几次运行的延迟与更广泛的图片无关,除非您对单次性能感兴趣。

    为了便于探索,您可以查看禁用 JIT 编译时代码的行为:将 -Xint 传递给 java 命令。还有更多的标志可以禁用优化的各个方面。

    关于performance - Java-重复的函数调用减少了执行时间,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32032095/

    10-10 06:43