performance - Scala 的 .min 如何避免装箱和拆箱的惩罚?

标签 performance scala boxing

Vector.minimplemented作为

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 中的时间,否则它会主导这一点,是的,我使我的基准测试升温......)。

How is the first version avoiding the performance penalty of the boxing?



编辑:这是我的分析代码:
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 毫秒,使用 reduceLeft约 200 毫秒。我已经使用 YourKit 分析了此代码;这是一个 screen grab的调用树显示 min不会导致任何拳击。

最佳答案

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

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

关于performance - Scala 的 .min 如何避免装箱和拆箱的惩罚?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10732496/

相关文章:

scala - Spark 结构化流 + Kafka 集成 : MicroBatchExecution PartitionOffsets Error

c# - 使用受约束的泛型而不是接口(interface)——缺点?

mysql - 使用单个mysql服务器时,多个数据库和单个数据库有什么区别?

c++ - 对大量数据组织逐个比较操作的最佳方式是什么?

scala - IntelliJ "Cannot infer Scala class path..."但 Gradle testCompile 是正确的?

scala - 使用相同谓词进行细化时,如何使用 Scala 的 Refined 库确保类型安全

c# - CIL - 装箱/拆箱与可空

Kotlin 盒装​​ Int 不一样

algorithm - 使用空间索引查找彼此范围内的点

android - 应用程序内容位于 android L 中的导航栏后面