【问题标题】:Is there or will there be a Scala collection extending Seq with faster iteration than Array?是否存在或是否会有一个 Scala 集合以比 Array 更快的迭代速度扩展 Seq?
【发布时间】:2019-08-14 08:36:51
【问题描述】:

根据我的测试,readArray 是通过foreachwhiletailrec 进行随机访问或迭代时最快的集合,但它们是可变的,与@987654327 不同@,不幸的是没有Array那么快。

我仍然坚持使用 Scala 2.11,但我最近发现 Scala 2.13 已经进行了更改。是否有希望存在或将存在一个在随机访问方面超过Array 的不可变集合?

这是Array[Double] 上的欧几里得距离示例,它在 Seq 后代上的工作原理完全相同。

    final def euclidean(v1: Array[Double], v2: Array[Double]): Double = {
      @annotation.tailrec
      def go(d: Double, i: Int): Double = {
        if(i < v1.size) { 
          val toPow2 = v1(i) - v2(i)
          go(d + toPow2 * toPow2, i + 1)
        }
        else d
      }
      sqrt(go(0D, 0))
    }

【问题讨论】:

  • 2.13 将有一个immutable Array
  • 我刚刚尝试使用tailrec 比较欧几里得距离,而 ArraySeq 运行 1M 时仍然慢约 10%。
  • tailrec 是什么意思?使用headtail 拆分集合的尾递归算法?如果是这样,您可能最好使用 List 而不是 Array。每个tail 调用都会将数组的内容复制到一个新的。 数组适用于迭代算法。
  • 在这种情况下我没有使用 tail 和 head,只需将 while 循环替换为尾递归调用以迭代 X &lt;: SeqArray
  • 能否分享问题中的代码。我不是集合方面的专家,但如果您查看源代码,immutable Array 只是普通 (mutable) 的包装器数组。所以,它们的行为应该非常相似,或者至少我相信如此。

标签: scala performance collections


【解决方案1】:

总的来说,我认为在 JVM 中的随机访问方面不可能超过Array。由于数组元素的大小相等,并且它们在内存中按顺序定位,因此可以使用给定的索引在恒定时间内快速计算出元素的位置。更重要的是,这会导致良好的缓存局部性。

在最好的情况下,集合可以具有与数组相当的随机访问性能。查看提到的ArraySeq 的 scala 2.11 源代码,它说:

这意味着元素 * 原始类型被装箱。

https://github.com/scala/scala/blob/2.11.x/src/library/scala/collection/mutable/ArraySeq.scala#L19

这很可能解释了观察到的 10% 的性能下降。数组有方法toSeq,它被实现为WrappedArray,并且每个原始类型都有专门的实现,我认为这是scala 2.11中性能最高的集合,用于包装数组https://github.com/scala/scala/blob/2.11.x/src/library/scala/collection/mutable/WrappedArray.scala#L173

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多