这个java基准测试发生了什么?

时间:2014-08-23 20:03:34

标签: java performance benchmarking

我正在使用junit运行这样的原始基准:

@Test
public void testTime() throws Exception{
    LoadoutBase<?> loadout = new LoadoutStandard("AS7-D-DC");

    final int iterations = 1000000;

    long start = System.nanoTime();
    int sum = 0;
    for(int i = 0; i < iterations; ++i){
        Iterator<Item> it = loadout.iterator();
        while( it.hasNext() ){
            sum += it.next().getNumCriticalSlots();
        }
    }
    long end = System.nanoTime();

    long time_it = end - start;

    start = System.nanoTime();
    sum = 0;
    for(int i = 0; i < iterations; ++i){
        for(Item item : loadout.getAllItems()){
            sum += item.getNumCriticalSlots();
        }
    }
    end = System.nanoTime();

    long time_arrays = end - start;

    System.out.println("it: " + time_it + " array: " + time_arrays + " diff: " + (double)time_it/time_arrays);
}

如果我设置iterations=1000000,那么我会

  

it:792771504数组:1109215387差异:0.7147137637029551

非常一致,但如果我设置iterations=10000,那么我得到

  

it:32365742 array:28902811 diff:1.1198129482976587

波动很大。 diff参数从0.7到1.2

有没有人能够了解这里可能发生的事情?我应该选择哪种方法?

编辑:

我真正的基准测试是幕后工作。 getAllItems创建一个新的List<Item>,并使用addAll获取16个子列表中的所有项目来填充它。 Iterator方法不构造此临时列表,而是跟踪它当前正在迭代的这16个子列表中的哪一个,并且具有一些逻辑以使16个子列表看起来像连续列表。

2 个答案:

答案 0 :(得分:4)

由于您要测试使用Iterator和使用增强型for循环(在幕后为您使用Iterator)之间的区别,然后您做错了。首先是因为JIT有足够的时间来改进第二种方法的结果,而不是第一种和其他几种原因:How do I write a correct micro-benchmark in Java?。你可以通过这些来看到非常不同的结果(再次,作为JIT的结果):

  • 添加一个循环,增加执行两次迭代的次数。这是一个涵盖所有代码的for循环。
  • 移动增强的for循环方法之前执行。

获得测试真实结果的最佳方法是将方法分成不同的方法,然后测量每个方法(除了JVM预热阶段和上一个QA中涵盖的其他内容)。另外,我建议你不要重新发明轮子并使用基于JUnit的适当基准框架。以下是其中两个:

相关问答/基准测试:

答案 1 :(得分:0)

在阅读了Luiggi Mendoza的链接后,我重构了我的测试代码:

@Test
public void testTime() throws Exception{

    LoadoutBase<?> loadout = new LoadoutStandard("AS7-D-DC");

    long start, end, sum;
    final int iterations = 10000;

    //WARMUP
    start = System.nanoTime();
    sum = 0;
    for(int i = 0; i < iterations; ++i){
        Iterator<Item> it = loadout.iterator();
        while( it.hasNext() ){
            sum += it.next().getNumCriticalSlots();
        }
    }
    end = System.nanoTime();
    //ENDOF WARMUP

    start = System.nanoTime();
    sum = 0;
    for(int i = 0; i < iterations; ++i){
        Iterator<Item> it = loadout.iterator();
        while( it.hasNext() ){
            sum += it.next().getNumCriticalSlots();
        }
    }
    end = System.nanoTime();
    long time_it = end - start;


    // WARMUP
    start = System.nanoTime();
    sum = 0;
    for(int i = 0; i < iterations; ++i){
        for(Item item : loadout.getAllItems()){
            sum += item.getNumCriticalSlots();
        }
    }
    end = System.nanoTime();
    // ENDOF WARMUP


    start = System.nanoTime();
    sum = 0;
    for(int i = 0; i < iterations; ++i){
        for(Item item : loadout.getAllItems()){
            sum += item.getNumCriticalSlots();
        }
    }
    end = System.nanoTime();
    long time_arrays = end - start;

    System.out.println("it: " + time_it + " array: " + time_arrays + " diff: " + (double)time_it/time_arrays);
}

现在我得到了一致的结果,说迭代器方法大约是getAllItems方法执行速度的0.7倍。即使我改变测试的顺序,结果也是一致的,所以我相信他们的测试。

感谢。