对Java8 Stream性能感到困惑

时间:2014-11-24 16:53:37

标签: java performance lambda java-8 performance-testing

我无法理解为什么使用Stream api在同一个数组上多次迭代 导致这样的表现!

请参阅下面的代码。

public class WhyIsDifferent {

public static void main(String[] args) {

    int[] values = getArray();
    Iterate(values, 598, 600); // 70 ms
    Iterate(values, 200, 202); // 0 ms
    Iterate(values, 700, 702); // 0 ms
    Iterate(values, 300, 310); // 1 ms
}

public static void Iterate(int[] values, int from, int to) {
    long start = System.currentTimeMillis();
    IntStream.of(values).filter(i -> i < to && i > from)
    .forEach(i -> 
        System.out.println(i) // do a something
    );
    System.out.println("Time:" + (System.currentTimeMillis() - start));
}

public static int[] getArray() {
    int[] values = new int[1000];
    for (int i = 0; i < 1000; i++) {
        values[i] = i;
    }
    return values;
}
}

肯定JVM优化了代码,但我不知道这是怎么回事?太神奇了! 你知道为什么会这样吗?

-

我正在测试Ubuntu 14.04 / / Oracle jdk / intel cpu。

1 个答案:

答案 0 :(得分:10)

它不是JIT编译器。这些70毫秒中的大部分花费在整个lambda子系统的初始化上(该逻辑的入口点可能是LambdaMetaFactory类),并且在lambda bootstrap调用(连接)上花费了很多时间。 阶段,如用户fge所述)。查看此方法,与您的方法相同,但分别测量所有步骤(并使用nanoTime):

public static void Iterate(int[] values, int from, int to) {
  long start = System.nanoTime();
  final IntPredicate predicate = i -> i < to && i > from;
  System.out.println("Predicate lambda creation time:" + NANOSECONDS.toMillis(System.nanoTime() - start));
  start = System.nanoTime();
  final IntConsumer action = System.out::println;
  System.out.println("Action lambda creation time:" + NANOSECONDS.toMillis(System.nanoTime() - start));
  start = System.nanoTime();
  final IntStream stream = IntStream.of(values).filter(predicate);
  System.out.println("Stream creation time:" + NANOSECONDS.toMillis(System.nanoTime() - start));
  start = System.nanoTime();
  stream.forEach(action);
  System.out.println("Stream consumption time:" + NANOSECONDS.toMillis(System.nanoTime() - start));
}

这是我机器上印刷的内容:

Predicate lambda creation time:53
Action lambda creation time:2
Stream creation time:2
599
Stream consumption time:1
Predicate lambda creation time:0
Action lambda creation time:0
Stream creation time:0
201
... all timings zero from here on...

您可以看到第一次调用的整个开销是在lambda创建部分(仅在第一次运行时,包括常规初始化和链接),并且流创建也需要一些时间。在所有情况下,实际流消耗都是零时间。

使用当前版本的HotSpot,这个效果绝对值得您关注:lambda bootstrap是一件昂贵的事情。

最后注意事项:如果您重新排序lambda创建语句,您将看到大部分时间都保留在第一个 lambda中。这表明它实际上只是第一次整体创建一个承担大部分初始化成本的lambda。