【问题标题】:Why stream is so slow? [duplicate]为什么流这么慢? [复制]
【发布时间】:2020-04-05 01:20:30
【问题描述】:

我已将此方法置于循环中,流方法比老式方法慢 3 到 4 倍...

正常吗?

    static double sumUtilStream(ArrayList<Toto> stats) { // Return the util of each stats
        return  stats.stream().mapToDouble(Toto::util).sum(); // That is slow !!!!
    }

    static double sumUtil(ArrayList<Toto> stats) { // Return the util of each stats
        double utils = 0;
        for (int i = 0; i <  stats.size(); i++) {
            utils = utils + stats.get(i).util(); 
        }
        return utils;
    }

这里是完整的代码测试:

class Toto {
    private double util = 0;

    public Toto(double value) {
        this.util = value;
    }

    public double util() { return this.util;}
}

class Main {
    static double sumUtilStream(ArrayList<Toto> totos) { // Return the util of each stats
        return  totos.stream().mapToDouble(Toto::util).sum(); // That is slow !!!!
    }

    static double sumUtil(ArrayList<Toto> totos) { // Return the util of each stats
        double utils = 0;
        for (int i = 0; i <  totos.size(); i++) {
            utils = utils + totos.get(i).util(); 
        }
        return utils;
    }
    public static void main(String args[])  { 
        ArrayList<Toto> totos = new ArrayList<Toto>();

        totos.add(new Toto(50));
        totos.add(new Toto(50));
        totos.add(new Toto(50));
        totos.add(new Toto(50));
        totos.add(new Toto(50));

        for (int i = 0; i <  100000000; i++) {
            sumUtil(totos);
        }
        System.out.println("finish");


    }   
}

【问题讨论】:

  • 是的。流比老式循环慢是正常的。但我也想看看你是如何让你的“慢 3 到 4 倍”的......因为由于基准测试缺陷,你的观察可能不正确。
  • 只需将完整的代码放在答案中...
  • ... 这意味着本来可能会回答您的问题的人会看到它有答案,然后继续前进。最好仅将“答案”框用于答案。我认为你应该编辑你的问题,在那里添加新信息。
  • 我对这个话题的看法与这里无关。请在 Quora ... 或其他讨论论坛上提出类似的问题。 StackOverflow 是一个问答网站,而不是讨论网站。旨在开始讨论或需要基于意见的答案的问题是题外话。

标签: java java-stream


【解决方案1】:

首先,您发布的基准有缺陷:

  1. 您没有采取任何措施来排除 JVM 预热效应。
  2. 您使用秒表测量时间的方法不可靠。
  3. 您的秒表测量包括启动和关闭 JVM 所需的所有时间。

如果您想编写一个能够产生我们可以依赖的结果的基准,请阅读How do I write a correct micro-benchmark in Java? 并听从它的建议。


对于您的问题:

正常吗?

是的,流比老式循环慢是正常的。 (实际差异取决于流在做什么,以及您使用的 Java 版本。)

另外,这不是一个新结果。如果你用 Google 搜索“java 流性能”,你会看到很多文章说 Java 流比循环慢。

为什么流这么慢?

这有各种详细的原因,但总体解释是循环更容易让 JIT 编译器优化。例如,考虑这一行:

  utils = utils + stats.get(i).util();

util() 在哪里

 public double util() { return this.util; }

JIT 编译器将能够内联 util() 调用并消除(可能)虚拟方法调用的开销。

在等效流中,对util() 的调用是通过作为参数传递给mapToDouble 的方法引用完成的。据优化器所知,mapToDouble 可以使用多个不同的方法引用来调用。因此,不能内联对特定方法的方法调用。

如果我们花时间全面比较和分析这两个版本,那么在其他地方,基于流的方法会涉及当前一代 JIT 编译器无法优化的开销。这可能会在未来的 Java 版本中改变......

简而言之:如果性能是您的主要目标,那么暂时不要使用流。

【讨论】:

    猜你喜欢
    • 2014-03-01
    • 1970-01-01
    • 2010-11-01
    • 2015-03-15
    • 2018-01-20
    • 2013-05-03
    • 2021-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多