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

2 回答 2

1

编写正确的微基准非常耗时且容易出错。我建议只使用已经可用的库(例如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 运行这两种方法仍然需要大约相同的时间,但优化得更好一些。

于 2014-02-14T09:07:48.430 回答
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 已经预热了它的内部函数并准备好服务他的脚趾。:)

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

于 2014-02-14T07:16:43.880 回答