对Java8 Stream性能感到困惑

Mor*_*Adi 5 java performance lambda performance-testing java-8

我无法理解为什么使用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;
}
}
Run Code Online (Sandbox Code Playgroud)

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

-

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

Mar*_*nik 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));
}
Run Code Online (Sandbox Code Playgroud)

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

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...
Run Code Online (Sandbox Code Playgroud)

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

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

最后注意事项:如果重新排序lambda创建语句,您将看到大部分时间都停留在要创建的第一个 lambda上.这向我们展示了它实际上只是lambda的第一次整体创建,它承担了大部分初始化成本.