问题描述
我正在使用junit运行原始基准测试,如下所示:
I'm using junit to run a primitive benchmark like this:
@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
,我会得到
非常一致,但是如果我设置iterations=10000
,我会得到
very consistently but if I set iterations=10000
then I get
波动很大. diff参数的范围是0.7到1.2
with very wild fluctuations. The diff parameters is anywhere from 0.7 to 1.2
任何人都可以对这里可能发生的事情有所了解吗?我应该选择哪种方法?
Could any one shed some light on what might be happening here? Which method should I choose?
我真正进行基准测试的是幕后工作. getAllItems
创建一个新的List<Item>
并通过使用addAll
从16个子列表中获取所有项目来填充它. Iterator
方法不是构造此临时列表,而是跟踪它当前在这16个子列表中的哪个列表中进行迭代,并具有使该16个子列表看起来像连续列表的逻辑.
What I really am benchmarking is behind the scenes work. getAllItems
creates a new List<Item>
and populates it by getting all items from 16 sublists using addAll
. The Iterator
approach doesn't construct this temporary list but rather keeps track of in which of these 16 sublists it is currently iterating and has some logic to make the 16 sublists look like a continuous list.
推荐答案
由于您要测试使用Iterator
和使用增强的for循环(在幕后使用Iterator
)之间的区别,因此您需要重新做错了.首先是因为JIT有足够的时间来改进第二种方法的结果,而不是第一种方法,这里解释了以下几个其他原因:我该怎么写Java中正确的微基准?.通过执行以下操作,您可能会看到非常不同的结果(同样是JIT的结果):
Since you want to test the difference between using Iterator
and using enhanced for loop (which uses Iterator
behind the scenes for you), then you're doing it wrong. First because JIT has enough time to improve the results on the second approach rather than in the first and several other reasons explained here: How do I write a correct micro-benchmark in Java?. You could see very different results of this by doing these (again, as result of JIT):
- 添加一个循环,该循环将增加执行两次迭代的次数.这是一个覆盖所有这些代码的
for
循环. - 移动增强的
for
循环方法,使其在之前执行.
- Add a loop that will increase the number of times to execute both iterations. This is, a
for
loop that covers all this code. - Moving the enhanced
for
loop approach to be executed before.
获得测试真实结果的最佳方法是将这些方法分为不同的方法,然后进行每种方法的评估(除了JVM预热阶段和上一QA涵盖的其他内容之外).另外,我建议您不要重新发明轮子,而应使用基于JUnit的适当基准测试框架.这是其中两个:
The best way to obtain real results for your test would be to split the approaches into different methods, then measure each (apart from the JVM warm up phase and other stuff covered in prev QA). Also, I recommend you to not reinvent the wheel and use a proper benchmark framework based on JUnit. Here are two of them:
- JUnitBenchmarks
- Caliper
基准测试的相关Q/A:
Related Q/As for benchmarking:
- arraylist vs linked list .why linked list is slower when we add in the end?
- Decreasing execution time of identical consecutive runs of a Java program
这篇关于这个Java基准测试中发生了什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!