gpt4 book ai didi

performance - Scala 函数式编程比传统编码慢吗?

转载 作者:行者123 更新时间:2023-12-03 06:42:04 24 4
gpt4 key购买 nike

在我第一次尝试创建函数代码时,我遇到了性能问题。

我从一个常见任务开始 - 将两个数组的元素相乘并对结果求和:

var first:Array[Float] ...
var second:Array[Float] ...
var sum=0f;
for (ix<-0 until first.length)
sum += first(ix) * second(ix);

以下是我改革工作的方法:

sum = first.zip(second).map{ case (a,b) => a*b }.reduceLeft(_+_)

当我对这两种方法进行基准测试时,第二种方法需要 40 倍的时间才能完成!

为什么第二种方法需要更长的时间?我怎样才能改革工作,既提高速​​度效率,又使用函数式编程风格?

最佳答案

这两个示例速度如此不同的主要原因是:

  • 速度更快的不使用任何泛型,因此不会面临装箱/拆箱。
  • 速度更快的不会创建临时集合,因此可以避免额外的内存复制。

让我们逐个考虑较慢的部分。第一:

first.zip(second)

这会创建一个新数组,一个 Tuple2 数组。它将把两个数组中的所有元素复制到 Tuple2 对象中,然后将对每个对象的引用复制到第三个数组中。现在,请注意 Tuple2 已参数化,因此它无法直接存储 Float。相反,为每个数字创建 java.lang.Float 的新实例,将数字存储在其中,然后将每个数字的引用存储到 Tuple2 中。

map{ case (a,b) => a*b }

现在第四个数组已创建。要计算这些元素的值,它需要从第三个数组中读取对元组的引用,读取对存储在其中的 java.lang.Float 的引用,读取数字、相乘、创建一个新的 java.lang.Float 来存储结果,然后将此引用传回,该引用将再次被 de 引用以存储在数组中(数组不是类型删除)。

不过,我们还没有完成。这是下一部分:

reduceLeft(_+_)

这个相对无害,除了它仍然在迭代时进行装箱/拆箱和 java.lang.Float 创建,因为 reduceLeft 接收 Function2,这是参数化的。

Scala 2.8 引入了一项称为特化的功能,它将消除大量此类装箱/拆箱。但让我们考虑其他更快的版本。例如,我们可以在一个步骤中执行 mapreduceLeft:

sum = first.zip(second).foldLeft(0f) { case (a, (b, c)) => a + b * c }

我们可以使用 view (Scala 2.8) 或 projection (Scala 2.7) 来避免完全创建中间集合:

sum = first.view.zip(second).map{ case (a,b) => a*b }.reduceLeft(_+_)

实际上,最后一个方法并没有节省太多,所以我认为如果很快“丢失”,则不严格(即,即使在 View 中,这些方法之一也是严格的)。默认情况下还有一种非严格的压缩替代方法(即避免一些中间结果):

sum = (first,second).zipped.map{ case (a,b) => a*b }.reduceLeft(_+_)

这给出了比前者更好的结果。比 foldLeft 好,尽管好不了多少。不幸的是,我们无法将 zippedfoldLeft 结合使用,因为前者不支持后者。

最后一个是我能得到的最快的。比这更快,只有特化。现在,Function2 恰好是专门针对 IntLongDouble 的。其他原语被排除在外,因为特化极大地增加了每个原语的代码大小。在我的测试中,尽管 Double 实际上花费了更长的时间。这可能是因为它的大小是原来的两倍,或者可能是我做错了什么。

因此,最终,问题是多种因素综合作用的结果,包括生成元素的中间副本,以及 Java (JVM) 处理原语和泛型的方式。 Haskell 中使用 super 编译的类似代码将等同于任何缺少汇编程序的代码。在 JVM 上,您必须意识到权衡并准备好优化关键代码。

关于performance - Scala 函数式编程比传统编码慢吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2794823/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com