Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Java8,列表的第一次处理比后续处理慢_Performance_Java 8_Java Stream - Fatal编程技术网

Performance Java8,列表的第一次处理比后续处理慢

Performance Java8,列表的第一次处理比后续处理慢,performance,java-8,java-stream,Performance,Java 8,Java Stream,为了检查Java8流和lambda的性能,我正在运行一些测试(非常基本,没有什么特别之处)。使用一个1000万POJO的ArrayList,我只想得到BigDecimal字段的平均值。为了获取多个样本,我运行了五次该过程,令我惊讶的是,这五次运行中的第一次运行速度比其他运行速度要慢得多。我第一次得到的值是0.38秒,其他四次得到的值是0.04秒。这是10倍的速度!!!我还使用老式的for(pojop:pojos)做了同样的测试,结果相似。为什么会发生这种情况,我如何利用它?我使用的代码是: fo

为了检查Java8流和lambda的性能,我正在运行一些测试(非常基本,没有什么特别之处)。使用一个1000万POJO的
ArrayList
,我只想得到
BigDecimal
字段的平均值。为了获取多个样本,我运行了五次该过程,令我惊讶的是,这五次运行中的第一次运行速度比其他运行速度要慢得多。我第一次得到的值是0.38秒,其他四次得到的值是0.04秒。这是10倍的速度!!!我还使用老式的
for(pojop:pojos)
做了同样的测试,结果相似。为什么会发生这种情况,我如何利用它?我使用的代码是:

for (int i = 0; i < 5; i++) {
    long init = System.nanoTime();
    BigDecimal sum = lista.parallelStream().map(x -> x.getCosto()).reduce(BigDecimal.ZERO, BigDecimal::add);
    BigDecimal avg = sum.divide(BigDecimal.valueOf(registros));
    long end = System.nanoTime();
    System.out.println("End of processing: " + avg + " in "
            + ((end - init) / 1000000000.0) + " seconds.");
}
for(int i=0;i<5;i++){
long init=System.nanoTime();
BigDecimal sum=lista.parallelStream().map(x->x.getCosto()).reduce(BigDecimal.ZERO,BigDecimal::add);
BigDecimal平均值=总和除法(BigDecimal.valueOf(registros));
long end=System.nanoTime();
System.out.println(“处理结束:+avg+“in”
+((end-init)/100000000.0)+“秒”;
}

当您第一次调用流API时,初始化流API需要一个恒定的延迟,包括以下步骤:

  • java.util.stream
    包加载许多助手类
  • java.lang.invoke
    包加载lambda生成类(如
    LambdaMetafactory
  • 为流管道中涉及的lambda和方法引用生成运行时表示(包括流API中内部使用的lambda)
  • 所有这些字节码的分层编译(解释器->C1 JIT->C2 JIT)。C2 JIT编译(生成最快代码)仅在特定数量的方法调用(如5000)或特定数量的后缘(如果方法内部有大循环,则循环迭代;如40000)后触发。当大多数代码未经C2编译时,其运行速度会慢得多。此外,JIT编译器线程需要一些CPU时间,这些时间可能用于实际计算
  • 对于并行流:初始化公共
    ForkJoinPool
    ,创建新线程
所有这些步骤只执行一次。当您再次使用流API时,大部分工作已经完成,因此连续启动要快得多


在您的特定情况下,您正在密集地使用堆,因此堆的扩大也可能是额外缓慢的原因。如果您的
-Xms
默认值太小,则垃圾收集器将执行几个完整的gc循环,直到将堆放大到合适的大小。您可以使用Xms==Xmx(例如
-Xmx1G-Xms1G
)运行测试,这可能会提高第一次迭代的速度。

不幸的是,进行性能测试并不是那么容易,特别是在与lambda表达式和方法引用相结合时。你需要使用适当的工具,比如JMH框架。我不同意重复标记。OP询问为什么第一次处理较慢。事实确实如此。即使OP使用JMH重写基准测试,第一次迭代也会比后续迭代慢得多。考虑到我们所说的是几十毫秒,而不是微秒或纳秒,OPs测量在方法上并不是那么糟糕。也许值得为问题的“我如何利用它?”部分添加一个一般答案:一般来说,避免代码重复,创建可重用类,等等。