【发布时间】:2016-11-29 05:24:47
【问题描述】:
我正在试验谓词。我试图实现用于在分布式系统中序列化问题的谓词。我写了一个简单的例子,其中测试函数只返回 true。我正在测量开销,我偶然发现了这个有趣的问题。与直接访问相比,在 for 循环中访问数组要慢 10 倍。
class Test {
public boolean test(Object o) { return true; }
}
long count = 1000000000l;
Test[] test = new Test[3];
test[0] = new Test();
test[1] = new Test();
test[2] = new Test();
long milliseconds = System.currentTimeMillis();
for(int i = 0; i < count; i++){
boolean result = true;
Object object = new Object();
for(int j = 0; j < test.length; j++){
result = result && test[j].test(object);
}
}
System.out.println((System.currentTimeMillis() - milliseconds));
但是,下面的代码几乎快了 10 倍。可以是什么 原因?
milliseconds = System.currentTimeMillis();
for(int i=0 ; i < count; i++) {
Object object = new Object();
boolean result = test[0].test(object) && test[1].test(object) && test[2].test(object);
}
System.out.println((System.currentTimeMillis() - milliseconds));
在我的 i5 上进行基准测试。
4567 毫秒 for 循环访问
297 毫秒用于直接访问
【问题讨论】:
-
好吧,在第一段代码中,您有一个内部循环,每次外部循环迭代总是迭代 3 次。在第二段代码中,不存在这样的循环,整个事情可以立即短路,而循环本身不能。
-
只是为了让事情更具可比性,如何将第一段代码中的内循环条件更改为
!result && j < test.length并初始化boolean result = false以具有相同的短路机会? -
在我看来,你刚刚获得了一个糟糕的微基准,优化器正在做一些事情来消除第二个 sn-p 中的大部分工作。
-
将一种方法放入名为
foo()的方法中,将另一种方法放入称为bar()的方法中,然后调用这些方法,可能有20种类型,交替,来自您的main方法。对我来说,在几次调用之后,这些方法将花费完全相同的时间。 (以java -server ...开头可能会有所帮助)。第一种方法可能是一个更复杂的标记,这可能是JIT稍后启动的原因,但最终没有区别。 -
附注:这不是一个合适的微基准。在这两种情况下,
result变量都没有使用,编译器可以基本上消除了整个程序。result变量在第一种方法中是读取和写入,但在第二种方法中只写入这一事实可能是优化器更容易的另一个原因找出整个代码实际上是无用的......
标签: java arrays performance-testing benchmarking