具有无限系列的Java Stream-API性能

Ami*_*ani 6 java performance lambda java-8 java-stream

我正在观察一些奇特的行为Java8和新的行为Stream-API.

我希望以下两个陈述的表现相同,但事实并非如此.

LongStream.iterate(1, n -> n + 1).limit(5000)
          .anyMatch(n -> isPerfectCube((n*n*n)+((n*n)*p)));
Run Code Online (Sandbox Code Playgroud)

与

LongStream.iterate(1, n -> n + 1)
          .anyMatch(n -> isPerfectCube((n*n*n)+((n*n)*p)));
Run Code Online (Sandbox Code Playgroud)

两个语句都应该返回true,并且我不会期望任何性能差异,因为它们都可以在找到的第一个匹配项上发生短路.这些陈述的唯一区别是,一个是在要迭代的数字范围的上限,而另一个不是.

有人可以向我解释为什么一个人跑得更快并且使用的内存比另一个少?

ass*_*ias 7

p对于较大的值,条件为真的有一些值n.例如p = 3,条件变为真实n = 50_331_648.在这种情况下,5000的限制当然会在性能方面获胜,但两次计算不会返回相同的结果.

我随机选择了一个p(3002),返回true n小于5000,结果非常接近(虽然版本limit稍微慢一点,可能是因为额外条件n < 5000).

基准测试结果(每次调用的微秒数anyMatch):

Benchmark                    Mode   Samples         Mean   Mean error    Units
c.a.p.SO24003674.limit       avgt         5      130.165        2.663    us/op
c.a.p.SO24003674.noLimit     avgt         5      126.876        2.440    us/op
Run Code Online (Sandbox Code Playgroud)

基准代码(使用jmh):

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Fork(1)
public class SO24003674 {

  private int p = 3002;

  @GenerateMicroBenchmark
  public boolean limit() {
    return LongStream.iterate(1, n -> n + 1).limit(5000)
              .anyMatch(n -> isPerfectCube((n * n * n) + ((n * n) * p)));
  }

  @GenerateMicroBenchmark
  public boolean noLimit() {
    return LongStream.iterate(1, n -> n + 1)
              .anyMatch(n -> isPerfectCube((n * n * n) + ((n * n) * p)));
  }

  private static boolean isPerfectCube(long n) {
    long tst = (long) (Math.cbrt(n) + 0.5);
    return tst * tst * tst == n;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这很有道理 - 谢谢.还要感谢发布microbenchmark (2认同)