2014-02-14 114 views
0

我尝试下面的代码:为什么调用函数比不调用函数更快?

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 
+4

快速问题 - 如果在代码中交换两个循环,结果如何? –

+4

可能的重复[如何在Java中编写正确的微基准?](http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java ) - 因为你如何测量不太可能产生任何有用的东西。 –

+0

无法在我的PC上确认 - 循环一次使用时间= 2,z = 18 循环两次使用时间= 5,z = 18. :-) – Smutje

回答

1

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

你的微基准有相当多的缺陷,这将导致不可预测的结果:

  1. 你正在做不热身。
  2. 您正在对主方法内的两种方法进行基准测试,从而给JIT编译器更难以优化代码的时间。
  3. 代码“z = x + y;”实际上降至“z = 9 + 9”;“并且在循环中不会改变,所以循环可以完全优化到简单表达式“z = 18”。

不管怎么说,这是与显卡做了相应的基准代码:

@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运行这两种方法仍然需要大致相同的时间,但优化得更好一些。

0

从阅读评论我有这个想法,尝试下面的代码

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有所回暖其内部功能和准备发球在他的脚趾。 :)

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