【问题标题】:Adding immutable Vectors添加不可变向量
【发布时间】:2011-06-01 22:53:29
【问题描述】:

我正在尝试更多地使用 scalas 不可变集合,因为这很容易并行化,但我遇到了一些新手问题。我正在寻找一种从操作中(有效地)创建新向量的方法。准确地说,我想要类似的东西

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 的工作的优点是,只要集合对此提供支持,它就可以并行运行。

谢谢

【问题讨论】:

    标签: scala scala-collections


    【解决方案1】:

    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
    

    当然,您需要在更长的阵列上(以及在具有四个内核的机器上)使用它来进行并行化以改善性能。

    【讨论】:

    • 补充一点:“Vector 不是专门用于Double”意味着将数字放在Vector 中,它们将被装箱到Double 包装器对象中。每次访问Vector 的元素时,所有的装箱和拆箱都会消耗大量性能。
    • 将一个专门的集合集合与主要的 Scala 发行版一起发布有多难?它会起作用吗?会不会比较地道?
    • @Alex Cruise - 这很棘手。集合存在于复杂的层次结构中,并且该层次结构中的几乎所有内容都需要专门化然后进行测试。然后有很多高阶魔法,但(对我来说,无论如何)如何将其与专业化完美融合并不完全清楚。
    • 谢谢!我想VectorArray 的不可变版本。那么Scala中没有不可变的数组吗? @Rex:你的解决方案比ParArray 有优势吗?
    • @Markus - ParArray 不是专门的。 Vector 的行为非常类似于不可变的 Array,但它也不是专门的。 Array 是一个例外的原因是它是一个普通的旧 Java 数组(每个原始类型都有不同的版本,加上 Object)。
    【解决方案2】:

    当您使用多个高阶方法时,您应该使用延迟构建的集合:

    v1.view zip v2 map { case (a,b) => a+b }
    

    如果您不使用视图或迭代器,则每个方法都会创建一个新的不可变集合,即使在不需要它们时也是如此。

    可能不可变代码不会像可变代码那样快,但惰性集合会大大缩短代码的执行时间。

    【讨论】:

    • 请注意,一旦他完成链接操作,他可能应该force 视图,因为每次使用这些操作时都会为元素重新计算这些操作。您应该解释何时使用视图较慢,以及强制使用它们是什么意思。
    【解决方案3】:

    数组不是类型擦除的,向量是。基本上,在处理无法克服的原语时,JVM 为Array 提供了优于其他集合的优势。 Scala 的specialization 可能会降低这一优势,但考虑到它们在代码大小方面的成本,它们不能在任何地方使用。

    【讨论】:

      猜你喜欢
      • 2023-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      • 1970-01-01
      • 2023-03-29
      相关资源
      最近更新 更多