当前位置 : 主页 > 网络安全 > 测试自动化 >

toString.map和toString.toArray.map的性能差异

来源:互联网 收集:自由互联 发布时间:2021-06-22
在编写欧拉问题时,我碰到了我认为奇怪的事情: toString.map方法比toString.toArray.map慢. 这是一个例子: def main(args: Array[String]) { def toDigit(num : Int) = num.toString.map(_ - 48) //2137 ms def toDigitFast
在编写欧拉问题时,我碰到了我认为奇怪的事情:

toString.map方法比toString.toArray.map慢.

这是一个例子:

def main(args: Array[String]) 
{
    def toDigit(num : Int) = num.toString.map(_ - 48) //2137 ms
    def toDigitFast(num : Int) = num.toString.toArray.map(_ - 48) //592 ms

    val startTime = System.currentTimeMillis;

    (1 to 1200000).map(toDigit)

    println(System.currentTimeMillis - startTime)
}

字符串上的方法映射不应该回退到数组上的映射吗?为什么会出现如此显着的差异? (注意,增加数量甚至会导致非阵列情况下的堆栈溢出).

原版的

可能是因为toString.map使用隐式的WrappedString,而toString.toArray.map使用隐式的WrappedArray来解析地图.

让我们看看地图,如TraversableLike中所定义:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
  val b = bf(repr)
  b.sizeHint(this)
  for (x <- this) b += f(x)
  b.result
}

WrappedString使用StringBuilder作为构建器:

def +=(x: Char): this.type = { append(x); this }

def append(x: Any): StringBuilder = {
  underlying append String.valueOf(x)
  this
}

对Any的String.valueOf调用在Char实例上使用Java Object.toString,可能先获取框.这些额外的操作可能是速度差异的原因,而“阵列”构建器的代码路径应该更短.

这是一个猜测,但必须衡量.

编辑

修改之后,一般的观点仍然存在,但是我引用了错误的含义,因为toDigit方法返回一个Int序列(或类似),而不是我误读的翻译字符串.

toDigit使用LowPriorityImplicits.fallbackStringCanBuildFrom [T]:CanBuildFrom [String,T,immutable.IndexedSeq [T]],T = Int,它只是推荐给一般的IndexedSeq构建器.

toDigitFast使用隐式类型为CanBuildFrom [Array [_],T,Array [T]]的直接数组,无可争议地更快.

为toDigit传递以下CBF明确地使两个方法相同:

object FastStringToArrayBuild {

  def canBuildFrom[T : ClassManifest] = new CanBuildFrom[String, T, Array[T]] {
    private def newBuilder = scala.collection.mutable.ArrayBuilder.make()
    def apply(from: String) = newBuilder
    def apply() = newBuilder
  }  

}
网友评论