当前位置: 代码迷 >> java >> 使用Java / Eclipse测试代码执行速度
  详细解决方案

使用Java / Eclipse测试代码执行速度

热度:19   发布时间:2023-08-02 10:27:38.0

我想测试这两个方法中的哪个执行得更快,但是根据我首先运行哪个方法,该方法似乎总是运行得较慢。 我怀疑Eclipse正在使用某种缓存机制来加快第二种方法的执行速度。

private static int method1(int n) {
    int result = 0;
    for (int i = 0; i < n + 1; ++i) {
        result += i;
    }
    return result;
}

private static int method2(int n) {
    int result = 0;
    int i = 0;
    while (i < n + 1) {
        result += i++;
    }
    return result;
}

这是我用来测试时间差异的主要功能。

long start, end;

start = new Date().getTime();
for (int i = 0; i < 100000; ++i) {
    method1(i);
}
end = new Date().getTime();
System.out.println(end - start); // 47

start = new Date().getTime();
for (int i = 0; i < 100000; ++i) {
    method2(i);
}
end = new Date().getTime();
System.out.println(end - start); // 32

使用 ,我得到以下结果(对于n的各种值),每个方法调用的得分以纳秒为单位(更小=更好):

Benchmark                          (n)  Mode  Samples          Score         Error  Units
c.a.p.SO31495089.method1             1  avgt       10          2.149        0.027  ns/op
c.a.p.SO31495089.method1        100000  avgt       10      34626.763      441.915  ns/op
c.a.p.SO31495089.method1    1000000000  avgt       10  322506247.405  6774340.047  ns/op
c.a.p.SO31495089.method2             1  avgt       10          2.159        0.028  ns/op
c.a.p.SO31495089.method2        100000  avgt       10      34581.273      571.416  ns/op
c.a.p.SO31495089.method2    1000000000  avgt       10  320011679.005  4049907.844  ns/op

第二轮:

Benchmark                          (n)  Mode  Samples          Score         Error  Units
c.a.p.SO31495089.method1             1  avgt       10          2.164        0.029  ns/op
c.a.p.SO31495089.method1        100000  avgt       10      34706.194      365.189  ns/op
c.a.p.SO31495089.method1    1000000000  avgt       10  320269697.300  1696038.683  ns/op
c.a.p.SO31495089.method2             1  avgt       10          2.160        0.040  ns/op
c.a.p.SO31495089.method2        100000  avgt       10      34627.163      325.981  ns/op
c.a.p.SO31495089.method2    1000000000  avgt       10  320698252.840  2332275.430  ns/op

底线:这两种方法的执行情况均与预期的相似(执行时间之差小于测量误差)。

使用new Date().getTime()指定挂钟时间 但这并不是开发人员真正想要的(在大多数情况下,直到进行使用企业级基准测试的基准测试为止 ),因为挂钟时间受许多后台进程影响,因此,Java提供了更复杂的API来进行测量时间。

为了排除其他系统活动的影响,您需要测量应用程序“用户时间”。

  • 用户时间 ”是运行应用程序自己的代码所花费的时间。
  • CPU时间 ”是用户时间加上系统时间。 这是为应用程序使用CPU所花费的总时间。

下面的示例演示使用ManagementFactory.getThreadMXBean() API的CPU和用户时间计算。

    Thread thread = new Thread(){
            public void run() {
                for (int i = 0; i < 100000; ++i) {
                    int result = 0;
                    for (int j = 0; j < i + 1; ++j) {
                        result += j;
                    }
                }
                System.out.println("FOR approach: ThreadCpuTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime()/1000000000d);
                System.out.println("FOR approach: UserTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadUserTime()/1000000000d);
            };
        };
        thread.start();

        Thread thread2 = new Thread(){
            public void run() {
                for (int i = 0; i < 100000; ++i) {
                    int result = 0;
                    int j = 0;
                    while (j < i + 1) {
                        result += j++;
                    }
                }
                System.out.println("WHILE approach: ThreadCpuTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime()/1000000000d);
                System.out.println("WHILE approach: UserTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadUserTime()/1000000000d);
            };
        };
        thread2.start();


话虽如此,我真的不确定为什么会出现意外行为,我在Eclipse和IntelliJ IDE中都运行了您的代码,而且我总是得到比WHILE循环快的FOR循环方法。

可能尝试重新启动Eclipse并运行较少的后台进程,或者不运行Eclipse,而是从Java命令行运行测试,以便确保结果

从下面的字节码分析中可以看出,WHILE和FOR循环方法生成的字节码相同 ,这意味着将有相同的汇编代码 ,因此CPU将花费相同的时间执行指令

但是实际上,当我们在您的IDE中运行或以其他方式运行时,则受后台进程的影响,因此观察到的时间不同。 但是在这种特殊情况下-WHILE v / s FOR,更适合进行字节码分析并得出WHILE和FOR循环方法将花费相同时间的结论。


FOR循环的字节码:

{
  public Test2();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: bipush        10
         5: if_icmpge     21
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: iload_1
        12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        15: iinc          1, 1
        18: goto          2
        21: return
      LineNumberTable:
        line 3: 0
        line 4: 8
        line 3: 15
        line 6: 21
      StackMapTable: number_of_entries = 2
           frame_type = 252 /* append */
             offset_delta = 2
        locals = [ int ]
           frame_type = 250 /* chop */
          offset_delta = 18

}

WHILE循环的字节码:

{
  public Test();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: bipush        10
         5: if_icmpge     21
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: iload_1
        12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        15: iinc          1, 1
        18: goto          2
        21: return
      LineNumberTable:
        line 3: 0
        line 4: 2
        line 5: 8
        line 6: 15
        line 8: 21
      StackMapTable: number_of_entries = 2
           frame_type = 252 /* append */
             offset_delta = 2
        locals = [ int ]
           frame_type = 18 /* same */

}

进一步阅读:

While和For Loop具有相似的性能。

也许这篇类似的文章对您帮助