【问题标题】:Why is iteration is faster than Streams in Java? [duplicate]为什么迭代比 Java 中的 Streams 快? [复制]
【发布时间】:2021-03-12 04:37:07
【问题描述】:

我测试了一个包含 1000 万个元素的数组,迭代总是比流更快。谁能解释一下原因?

String[] words = new String[10000000];
Arrays.fill(words, "hello world!");

Instant start = Instant.now();
long count = 0;
for (String word : words) {
    if (word.length() > 8)
        count++;
}
Instant end = Instant.now();
System.out.println("Using iterations:" + count + " in  " + Duration.between(start, end).toMillis());

start = Instant.now();
count = Arrays.stream(words).parallel().filter(word -> word.length() > 8).count();
end = Instant.now();
System.out.println("Using Streams   :" + count + " in  " + Duration.between(start, end).toMillis());

示例运行

Using iterations:10000000 in  13
Using Streams   :10000000 in  53

【问题讨论】:

  • 我的猜测是,由于您正在执行的操作非常简单(比较两个数字一次),因此流的开销非常大。另外,if 语句始终运行,因此分支预测可以使循环显着加快。但在此之前,请使用合适的基准测试库,如 JMH。
  • 它并不总是更快。这取决于示例。它还可能取决于您使用的 Java 版本。 (预计流在未来会变得更快。)
  • 你不是在这里比较苹果和苹果。一个可能的问题是您在流的情况下使用parallel。试试没有那个。如果正在执行的任务太小,提交和运行任务的开销可能会淹没使用多核的潜在加速。
  • @StephenC 这正是我的想法——如果他重新删除 parallel() 我猜他可能在 30 岁以下的流案例中。当然,过滤器阶段也可能会产生一个必须增长或缩小(并且并行)的中间结果

标签: java java-stream


【解决方案1】:

无法用 JMH 重现:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class Streams {
    String[] words;

    @Setup
    public void setup() {
        words = new String[10_000_000];
        Arrays.fill(words, "hello world!");
    }

    @Benchmark
    public long forLoop() {
        long count = 0;
        for (String word : words) {
            if (word.length() > 8)
                count++;
        }
        return count;
    }

    @Benchmark
    public long stream() {
        return Arrays.stream(words).filter(word -> word.length() > 8).count();
    }

    @Benchmark
    public long parallelStream() {
        return Arrays.stream(words).parallel().filter(word -> word.length() > 8).count();
    }
}

结果:

Benchmark               Mode  Cnt   Score   Error  Units
Streams.forLoop         avgt    5   8,408 ? 0,086  ms/op
Streams.parallelStream  avgt    5   3,943 ? 0,353  ms/op
Streams.stream          avgt    5  12,891 ? 0,064  ms/op

正如预期的那样,并行流比 for 循环快,而 for 循环比非并行流快。

使用right tools 衡量性能。

【讨论】:

  • 当然,与他的 X86 相比,您的 24 核 CPU 可能也有帮助 :-)
  • 可能你的 JDK 和作者使用的不一样。
  • 这两个问题都指向了 OP 方法的缺陷。 Java 基准测试结果应说明测试中使用的硬件、操作系统和(精确的)Java 版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
  • 1970-01-01
  • 2014-02-22
相关资源
最近更新 更多