10

Vector.min实现

def min[B >: A](implicit cmp: Ordering[B]): A = {
  if (isEmpty)
    throw new UnsupportedOperationException("empty.min")
  reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y)
}

当你分析

Vector.fill(1000000)(scala.util.Random.nextLong).min

它很快,没有装箱或拆箱。然而,如果你写了明显等价的

val cmp = implicitly[Ordering[Long]]
Vector.fill(1000000)(scala.util.Random.nextLong).reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y)

它的运行速度大约慢了 10 倍(忽略 Random 中的时间,否则它会占主导地位,是的,我预热了我的基准测试......)。

第一个版本如何避免拳击的性能损失?

编辑:这是我的分析代码:

val cmp = implicitly[Ordering[Long]]

def randomLongs = Vector.fill(1000000)(scala.util.Random.nextLong)

def timing[R](f: => R): (Long, R) = {
  val startTime = System.nanoTime
  val result = f
  ((System.nanoTime - startTime) / 1000000, result)
}

def minTiming = { val r = randomLongs; timing(r.min)._1 }
def reduceLeftTiming = { val r = randomLongs; timing(r.reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y))._1 }

while(true) {
  println((minTiming, reduceLeftTiming))
}

而且我看到使用min时间约为 20 毫秒,使用时间约为 200 毫秒reduceLeft。我已经使用YourKit;分析了这段代码。这是调用树的屏幕截图,显示min不会导致任何装箱。

4

1 回答 1

5

我认为第一个版本推断java.lang.LongB. 所以仍然有装箱,但只是在填充向量时,然后所有的比较都是在装箱的对象之间进行的。

在第二个版本中,由于 type ofcmp给出为Ordering[Long]java.lang.Long向量中的 s 在传递给 之前必须拆箱cmp.lteq(x, y)

于 2012-05-24T08:34:31.807 回答