我正在试验谓词。我尝试实现谓词来序列化分布式系统中的问题。我写了一个简单的例子,其中test函数只返回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毫秒用于循环访问
直接访问297毫秒
答案 0 :(得分:1)
如果循环标头需要一个单位时间来执行第一个解决方案循环标头评估需要3N个单位时间。在直接访问时需要N.
除了第一解决方案3&amp;&amp;每次迭代的条件评估,而在第二次只有2。
最后但并非最不重要的布尔短路评估会导致您的第二个更快的例子,即“过早地”停止测试条件,即如果第一个&amp;&amp;和整个结果评估为假。条件结果错误。
答案 1 :(得分:1)
由于test(Object o)
的可预测结果,编译器能够非常有效地优化第二段代码。第一段代码中的第二个循环使得这种优化成为不可能。
将结果与以下Test
类进行比较:
static class Test {
public boolean test(Object o) {
return Math.random() > 0.5;
}
}
......和循环:
long count = 100000000l;
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));
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));
现在两个循环几乎需要相同的时间:
run:
3759
3368
BUILD SUCCESSFUL (total time: 7 seconds)
p.s。: 有关JIT编译器优化的更多信息,请查看this article。
答案 2 :(得分:1)
您几乎承担了使用微基准测试所能犯的所有基本错误。