我正在尝试使用scalas immutable集合进行更多工作,因为这很容易并行化,但我遇到了一些新手问题。我正在寻找一种从操作中创建(有效)新Vector的方法。确切地说,我想要像
这样的东西val v : Vector[Double] = RandomVector(10000)
val w : Vector[Double] = RandomVector(10000)
val r = v + w
我测试了以下内容:
// 1)
val r : Vector[Double] = (v.zip(w)).map{ t:(Double,Double) => t._1 + t._2 }
// 2)
val vb = new VectorBuilder[Double]()
var i=0
while(i<v.length){
vb += v(i) + w(i)
i = i + 1
}
val r = vb.result
}
与使用Array的工作相比,两者都需要很长时间:
[Vector Zip/Map ] Elapsed time 0.409 msecs
[Vector While Loop] Elapsed time 0.374 msecs
[Array While Loop ] Elapsed time 0.056 msecs
// with warm-up (10000) and avg. over 10000 runs
有更好的方法吗?我认为使用zip / map / reduce的工作具有以下优势:只要集合支持此功能,它就可以并行运行。
由于
答案 0 :(得分:5)
Vector
并非专门用于Double
,因此您将使用它来支付相当大的性能损失。如果您正在进行简单的操作,那么最好在单个核心上使用阵列,而不是整个机器上的Vector
或其他通用集合(除非您有12个以上的核心)。如果您仍然需要并行化,则可以使用其他机制,例如使用scala.actors.Futures.future
创建实例,每个实例都在范围的一部分上执行工作:
val a = Array(1,2,3,4,5,6,7,8)
(0 to 4).map(_ * (a.length/4)).sliding(2).map(i => scala.actors.Futures.future {
var s = 0
var j = i(0)
while (j < i(1)) {
s += a(j)
j += 1
}
s
}).map(_()).sum // _() applies the future--blocks until it's done
当然,您需要在更长的阵列(以及具有四个核心的计算机上)上使用它来进行并行化以改进。
答案 1 :(得分:4)
当您使用多个高阶方法时,您应该使用延迟构建的集合:
v1.view zip v2 map { case (a,b) => a+b }
如果不使用视图或迭代器,即使不需要它们,每个方法也会创建一个新的不可变集合。
可能不可变的代码不会像mutable一样快,但是惰性集合会大大缩短代码的执行时间。
答案 2 :(得分:4)
数组不是类型擦除的,矢量是。基本上,在处理无法克服的原语时,JVM使Array
优于其他集合。 Scala的specialization
可能会降低这一优势,但考虑到代码大小的成本,它们无法在任何地方使用。