我有以下代码
public class BenchMark {
public static void main(String args[]) {
doLinear();
doLinear();
doLinear();
doLinear();
}
private static void doParallel() {
IntStream range = IntStream.range(1, 6).parallel();
long startTime = System.nanoTime();
int reduce = range
.reduce((a, item) -> a * item).getAsInt();
long endTime = System.nanoTime();
System.out.println("parallel: " +reduce + " -- Time: " + (endTime - startTime));
}
private static void doLinear() {
IntStream range = IntStream.range(1, 6);
long startTime = System.nanoTime();
int reduce = range
.reduce((a, item) -> a * item).getAsInt();
long endTime = System.nanoTime();
System.out.println("linear: " +reduce + " -- Time: " + (endTime - startTime));
}
}
我试图对流进行基准测试,但在一次又一次调用相同的函数时,执行时间逐渐减少
输出:
linear: 120 -- Time: 57008226
linear: 120 -- Time: 23202
linear: 120 -- Time: 17192
linear: 120 -- Time: 17802
Process finished with exit code 0
第一次和第二次执行时间存在巨大差异。
我确信 JVM 可能在幕后做一些把戏,但有人可以帮助我了解那里到底发生了什么吗?
是否有办法避免这种优化,以便我可以对真实的执行时间进行基准测试?
最佳答案
I'm sure JVM might be doing some tricks behind the scenes but can anybody help me understand whats really going on there?
第一次调用的巨大延迟是由于整个 lambda 运行时子系统的初始化造成的。您只需为整个申请支付一次费用。
当您的代码第一次到达任何给定的 lambda 表达式时,您需要为该 lambda 的链接付费(
invokedynamic
调用站点的初始化)。经过一些迭代后,由于 JIT 编译器优化了您的缩减代码,您将看到额外的加速。
Is there anyway to avoid this optimization so I can benchmark true execution time?
您在这里提出了一个矛盾:“真实”执行时间是在应用所有优化后预热后获得的执行时间。这是实际应用程序将经历的运行时。前几次运行的延迟与更广泛的情况无关,除非您对单次性能感兴趣。
为了进行探索,您可以查看禁用 JIT 编译时代码的行为方式:将 -Xint
传递给 java
命令。还有更多标志可以禁用优化的各个方面。
关于performance - Java - 重复函数调用减少执行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44931750/