【问题标题】:Why is functional faster than imperative for large amounts of data and slower than imperative for small amounts of data?为什么函数式处理大量数据时比命令式要快,而对于少量数据,函数式比命令式要慢?
【发布时间】:2019-09-03 12:50:16
【问题描述】:

我想比较循环和流的性能。为此,我写了 2 个方法。两者都过滤掉以“A”开头的名称并以字符串形式返回它们。 如果我使用 50.000 个随机生成的名称来执行此操作,那么命令式方法会更快。但是,如果我使用 500.000 个随机生成的名称来执行此操作,那么函数方式会更快。

我的问题是,为什么小数据集的函数范式较慢而大数据集的函数范式较快?流是否需要大量时间来初始化,但在此之后它们会更高效?

public String imperativeArray() {

String result = "";
  for(String name : arraytestSet) {
    if(name.startsWith("A")) {
       if(result.isEmpty()) {
          result += name;
       } else {
          result += "," + name;
       }
    }
  }
   return result;
}

public String functionalArray() {
   return Arrays.stream(arraytestSet)
     .filter(e -> e.startsWith("A"))
     .collect(Collectors.joining(","));
}

【问题讨论】:

  • 一方面,因为您在命令式案例中使用了简单的字符串连接。尝试改用StringBuilder
  • 处理小数字时,迭代解决方案应该更好,因为创建流的开销。在幕后,流将您的问题分解成更小的部分并执行它们,但这仅对大型数据集有好处。
  • @AndyTurner 我知道在某些情况下,如果 Java 编译器看到连接,它会使用 StringBuilder。这不是循环工作吗?
  • @SamOrozco no..
  • 编译器无法识别为所有循环使用一个字符串生成器会更有效。它将为每个 if 和 else 分支执行创建一个新的 stringbuilder!如有疑问,请运行 javap 并查看字节码!

标签: java performance arraylist functional-programming java-stream


【解决方案1】:

命令式和函数式之间不应该有任何性能差异。函数式编程将通过使用预定义的函数来提高代码的可读性。在内部,他们必须进行类似类型的处理。函数式风格的主要优点之一是您可以一眼看懂代码。 并行流可以比您的命令式代码更快,但是如果您确定数据将是巨大的并且可以从并行处理中受益,则可以使用并行流。否则并行流将比普通流慢。 来到您的示例代码,我觉得通过使用 Collectors.joining 您可以获得比 if-else 检查的性能优势,因为您正在使用字符串追加操作,该操作将在每次追加时继续创建一个新的字符串对象。但是collectors.joining 在内部使用StringBuilder,因此每次添加时它都会作用于单个对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-04-12
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    相关资源
    最近更新 更多