【问题标题】:Why is calling a function faster than not calling a function?为什么调用函数比不调用函数快?
【发布时间】:2014-02-14 06:56:56
【问题描述】:

我尝试了以下代码:

public class Test {
    public static void main(String[] args) {
        int x = 9, y = 9, z = 0;
        long startTime = System.currentTimeMillis();
        // System.out.println("loop one start time = " + startTime);
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                z = x + y;
            }
        }
        System.out.println("loop one use time = " + (System.currentTimeMillis() - startTime) + ",z = " + z);

        startTime = System.currentTimeMillis();
        // System.out.println("loop two start time = " + startTime);
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                z = sum(x, y);
            }
        }
        System.out.println("loop two use time = " + (System.currentTimeMillis() - startTime) + ",z = " + z);

    }

    public static int sum(int x, int y) {
        int t;
        t = x + y;
        return t;
    }
}

控制台的输出是:

loop one use time = 216,z = 18
loop two use time = 70,z = 18.

似乎第二个循环比第一个循环花费的时间更少! 我不明白为什么会这样。谢谢你的帮助。


更新: 我交换了两个循环,现在循环一个需要更少的时间!!

loop two use time = 219,z = 18
loop one use time = 69,z = 18

【问题讨论】:

  • 快速提问 - 如果在代码中交换两个循环会产生什么结果?
  • How do I write a correct micro-benchmark in Java? 的可能副本 - 因为您的测量方式不太可能产生任何有用的信息。
  • 无法在我的电脑上确认 - 循环一使用时间 = 2,z = 18 循环二使用时间 = 5,z = 18。:-)
  • 我改变了两个循环,现在循环一个更短了!!循环二使用时间 = 219,z = 18 循环一使用时间 = 69,z = 18。它喜欢第一个循环使用更长的时间。
  • 因此,将 Brians 的评论作为答案,人们可​​以说:“你测量错误。你得到的数字并不意味着任何有用的东西。”。这取决于操作系统和 JVM 做什么,它使用什么样的 JIT 编译等等。

标签: java function methods microbenchmark


【解决方案1】:

Writing a correct micro-benchmark 非常耗时且容易出错。我建议只使用已经可用的库进行微基准测试,例如Caliper,专门为此而设计的。

你的微基准有很多缺陷,会导致不可预知的结果:

  1. 您没有进行热身。
  2. 您在 main 方法中对这两种方法进行基准测试,从而使 JIT 编译器更难优化代码。
  3. 代码“z = x + y;”实际上归结为“z = 9 + 9;”并且在循环期间永远不会改变,因此可以将循环完全优化为简单的表达式“z = 18”。

无论如何,下面是使用 Caliper 完成的相应基准测试的代码:

@VmOptions("-server")
public class Test {

    @Benchmark
    public int timeSum1(long reps) {
        int dummy = 0; 
        int x = 9, y = 9;
        for (int j = 0; j < reps; j++) {
            dummy = x + y;
        }
        return dummy;
    }

    @Benchmark
    public int timeSum2(long reps) {
        int dummy = 0; 
        int x = 9, y = 9;
        for (int j = 0; j < reps; j++) {
            dummy = sum(x, y);
        }
        return dummy;
    }

    public static int sum(int x, int y) {
        int t;
        t = x + y;
        return t;
    }
}

您可以在此处查看此基准测试的结果:

结果如预期:两种方法花费的时间大致相同,因为它们可以被 JIT 编译器内联。使用 -server 运行这两种方法仍然需要大约相同的时间,但优化得更好。

【讨论】:

    【解决方案2】:

    从阅读cmets我得到了这个想法,试试下面的代码

    public class Test {
        public static void main(String[] args) {
            int x = 9, y = 9, z = 0;
            for (int i = 0; i < 10000; i++) {
                for (int j = 0; j < 10000; j++) {
                    z = x + y;
                    // z = sum(x, y);
                }
            }
            long startTime = System.currentTimeMillis();
            // System.out.println("loop one start time = " + startTime);
            for (int i = 0; i < 10000; i++) {
                for (int j = 0; j < 10000; j++) {
                    z = x + y;
                }
            }
            System.out.println("loop one use time = "
                    + (System.currentTimeMillis() - startTime) + ",z = " + z);
    
            startTime = System.currentTimeMillis();
            // System.out.println("loop two start time = " + startTime);
            for (int i = 0; i < 10000; i++) {
                for (int j = 0; j < 10000; j++) {
                    z = sum(x, y);
                }
            }
            System.out.println("loop two use time = "
                    + (System.currentTimeMillis() - startTime) + ",z = " + z);
    
        }
    
        public static int sum(int x, int y) {
            int t;
            t = x + y;
            return t;
        }
    }
    

    什么结果将表明两个循环具有相同的时间,因为 JVM 已经预热了它的内部函数并准备好服务他的脚趾。 :)

    这也意味着你不能直接将某些代码使用的时间与其算法直接相关,那么你需要控制相同的环境和参数来控制代码的时间消耗。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-02
      • 1970-01-01
      • 2011-04-30
      • 2021-04-01
      • 2017-05-29
      • 1970-01-01
      • 1970-01-01
      • 2013-03-14
      相关资源
      最近更新 更多