我正在比较两个atoi实现的性能。首先是使用charAt迭代输入字符串以获取字符;第二个是使用foldLeft

object Atoi {
  def withRandomAccess(str: String, baze: Int): Int = {
      def process(acc: Int, place: Int, str: String, index: Int): Int =
        if (index >= 0) process(acc + value(str.charAt(index)) * place, place * baze, str, index-1) else acc
      process(0, 1, str, str.length - 1)
    }

  def withFoldLeft(str: String, base: Int): Int = (0/:str) (_ * base + value(_))

  def value(c: Char): Int = { /* omitted for clarity */ }

  def symbol(i: Int): Char = { /* omitted for clarity */ }
}


foldLeft版本慢2到4倍(完整的基准代码是here)。我没想到这一点。你知道为什么吗? Scala是否在处理字符串之前将其转换为List?您是否有关于如何提高字符串的foldLeft性能的提示?

最佳答案

问题与内联无关,与使用Char时发生的foldLeft装箱/拆箱有关。

通过隐式转换为非专门的foldLeft,可以在String上获得StringOps。必须将字符串中的每个char装箱到java.lang.Character中,以便传递到Function2(与foldLeft的参数),然后再拆箱(便宜得多),以传递到内部的value方法中函数主体,然后再次装箱以放入折叠的下一个迭代中。

装箱涉及创建对象并随后对其进行垃圾收集的开销。



在避免拳击方面,有一个简短而重要的观点:


您不应该尝试避免拳击的机率几乎为1。


(也就是说,除非您确定了拳击造成的特定且不可接受的性能下降,否则您不必担心。)

如果您确定有一个需要解决的问题,请避免使用集合和for -comprehensions(在内部使用foreachflatMap)。如果使用循环,请使用while

07-26 08:36