添加不可变的向量

时间:2011-06-01 10:53:34

标签: scala scala-collections

我正在尝试使用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的工作具有以下优势:只要集合支持此功能,它就可以并行运行。

由于

3 个答案:

答案 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可能会降低这一优势,但考虑到代码大小的成本,它们无法在任何地方使用。