Scala:IndexedSeq.newBuilder与ArrayBuffer

时间:2017-10-29 15:09:56

标签: scala

我已经接受在循环中构建一个IndexedSeq应该使用一个ArrayBuffer,然后通过" .toVector()"转换为Vector。

在一个示例中,profiled显示了CPU热点在本节中,因此我尝试了另一种方法:使用IndexedSeq.newBuilder(),然后转换为immutable via" .result()"。

这一变化带来了显着的性能提升。代码看起来几乎相同。所以似乎使用IndexedSeq.newBuilder()是最佳实践。它是否正确?示例方法如下所示,ArrayBuffer差异已注释掉。

def interleave[T](a: IndexedSeq[T], b: IndexedSeq[T]): IndexedSeq[T] = {

  val al = a.length
  val bl = b.length

  val buffer = IndexedSeq.newBuilder[T]
  //---> val buffer = new ArrayBuffer[T](al + bl)
  val commonLength = Math.min(al, bl)
  val aExtra = al - commonLength
  val bExtra = bl - commonLength

  var i = 0
  while (i < commonLength) {
    buffer += a(i)
    buffer += b(i)
    i += 1
  }

  if (aExtra > 0) {
    while (i < al) {
      buffer += a(i)
      i += 1
    }
  } else if (bExtra > 0) {
    while (i < bl) {
      buffer += b(i)
      i += 1
    }
  }

  buffer.result()
  //---> buffer.toVector()
}

2 个答案:

答案 0 :(得分:3)

至于哪个最佳实践,我想这取决于您的要求。这两种方法都是可以接受和理解的。在所有条件相同的情况下,在这种特殊情况下,我赞成IndexedSeq.newBuilder超过ArrayBuilder(因为后者的目标是创建Array,而前者的结果是Vector)。

基准测试中只有一点:由于缓存, JIT &amp; HotSpot 性能,垃圾回收等。您可能会考虑使用的一个软件是 ScalaMeter 。您需要编写函数的两个版本来填充最终向量, ScalaMeter 将为您提供准确的统计信息。 ScalaMeter 允许代码在进行测量之前预热,还可以查看内存要求和CPU时间。

答案 1 :(得分:0)

在这个例子中,非正式测试没有欺骗,但ScalaMeter确实提供了更清晰的性能图。在ArrayBuffer(顶部橙色线)中构建结果肯定比更直接的newBuilder(蓝线)慢。

将IndexBuffer作为IndexedSeq返回是最快的(绿线),但它当然不会为您提供对不可变集合的真正保护。

在Array(红线)中构建中间结果是ArrayBuffer和newBuilder之间的中间步。

ScalaMeter Offline Report

&#34; zipAll&#34; collection方法允许以更实用的方式完成交错:

  def interleaveZipAllBuilderPat[T](a: IndexedSeq[T], b: IndexedSeq[T]): IndexedSeq[T] = {
    a.zipAll(b, null, null).foldLeft(Vector.newBuilder[T]) { (z, tp) =>
      tp match {
        case ((x:T, null)) => z += x
        case ((x:T,y:T)) => z += x += y
      }
    }.result()
  }

最慢的是函数方法,前两个几乎相同,这些区别仅在于一个模式匹配,另一个是if语句,因此模式不慢。

如果使用ArrayBuffer来累积结果,则函数比直接循环方法稍差,但使用newBuilder的直接循环要快得多。

如果&#34; zipAll&#34;可以返回构建器,如果构建器是可迭代的,函数样式可以更快 - 如果下一步只需要迭代元素,则不需要产生不可变结果。

Functional style performance

所以对我来说 newBuilder 是明显的赢家。