gpt4 book ai didi

scala - 为什么在 Scala 中压缩比 zip 快?

转载 作者:行者123 更新时间:2023-12-02 10:55:35 24 4
gpt4 key购买 nike

我编写了一些 Scala 代码来对集合执行元素操作。在这里,我定义了两个执行相同任务的方法。一种方法使用 zip其他用途zipped .

def ES (arr :Array[Double], arr1 :Array[Double]) :Array[Double] = arr.zip(arr1).map(x => x._1 + x._2)

def ES1(arr :Array[Double], arr1 :Array[Double]) :Array[Double] = (arr,arr1).zipped.map((x,y) => x + y)

为了在速度方面比较这两种方法,我编写了以下代码:
def fun (arr : Array[Double] , arr1 : Array[Double] , f :(Array[Double],Array[Double]) => Array[Double] , itr : Int) ={
val t0 = System.nanoTime()
for (i <- 1 to itr) {
f(arr,arr1)
}
val t1 = System.nanoTime()
println("Total Time Consumed:" + ((t1 - t0).toDouble / 1000000000).toDouble + "Seconds")
}

我调用 fun方法和通行证 ESES1如下:
fun(Array.fill(10000)(math.random), Array.fill(10000)(math.random), ES , 100000)
fun(Array.fill(10000)(math.random), Array.fill(10000)(math.random), ES1, 100000)

结果表明,该方法名为 ES1使用 zipped比方法更快 ES使用 zip .
基于这些观察,我有两个问题。

为什么是 zippedzip 快?

有没有更快的方法对 Scala 中的集合进行元素操作?

最佳答案

回答你的第二个问题:

Is there any more faster way to do element wise operation on a collection in Scala?


可悲的事实是,尽管它简洁、提高了生产力和对错误的适应能力,但函数式语言不一定是最高效的。在 OP 的示例中,使用高阶函数来定义要针对集合执行的投影具有开销,并且紧密循环会放大这一点。正如其他人指出的那样,中间和最终结果的额外存储分配也会产生开销。
如果性能很重要,尽管绝不是通用的,在像您这样的情况下,您可以将简洁的功能代码展开回命令式等效代码,以便重新获得对内存使用的更直接控制并消除函数调用开销。
在您的具体示例中, zipped可以通过预先分配正确大小的固定可变数组来强制执行求和(因为当其中一个集合用完元素时 zip 停止),然后将适当索引处的元素添加在一起(因为按序数索引访问数组元素是一个非常快的操作)。
例如,添加第三个函数, ES3到您的测试套件:
def ES3(arr :Array[Double], arr1 :Array[Double]) :Array[Double] = {
val minSize = math.min(arr.length, arr1.length)
val array = Array.ofDim[Double](minSize)
for (i <- 0 to minSize - 1) {
array(i) = arr(i) + arr1(i)
}
array
}
在我的 i7 上,我得到以下响应时间:
OP ES Total Time Consumed:23.3747857Seconds
OP ES1 Total Time Consumed:11.7506995Seconds
--
ES3 Total Time Consumed:1.0255231Seconds
更令人发指的是对两个数组中较短的数组进行直接就地变异,这显然会破坏这个较短数组的内容,因此只有在不需要原始数组进行进一步工作时才应该实现调用者:
def ES4(arr :Array[Double], arr1 :Array[Double]) :Array[Double] = {
val minSize = math.min(arr.length, arr1.length)
val array = if (arr.length < arr1.length) arr else arr1
for (i <- 0 to minSize - 1) {
array(i) = arr(i) + arr1(i)
}
array
}

Total Time Consumed:0.3542098Seconds
但显然,直接改变作为参数传递的数组元素并不符合 Scala 的精神——这段代码有副作用。
老实说,如果您需要在紧密循环中进行这种级别的性能优化,那么最好用 Rust、Go 或 C 编写这些类型的算法。

关于scala - 为什么在 Scala 中压缩比 zip 快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59598239/

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