严格收集与视图的性能比较

时间:2015-09-30 13:51:12

标签: performance scala collections profiling lazy-evaluation

我在Scala中对集合执行多个后续转换之间进行性能比较,这些转换是严格(急切执行评估)和非严格(懒惰执行评估)。

def time[R](block: => R): R = {
    val t0 = System.nanoTime()
    val result = block // call-by-name
    val t1 = System.nanoTime()
    println("Elapsed time: " + (t1 - t0)/1e9 + "s")
    result
}

/* A view on a collection makes all transformations lazy, which makes it
   possible to combine multiple transformations into one. */

// The non-lazy (eager) version:
time {
    (1 to 1e7.toInt).map(_ + 2).map(x => {
        if(x % 2 != 0) -x else x
    }).sum
}

// The lazy version using a view:
time {
    (1 to 1e7.toInt).view.map(_ + 2).map(x => {
        if(x % 2 != 0) -x else x
    }).force.sum
}

在我的笔记本电脑上,渴望版本的首次运行比懒惰版本慢。见下面的时间。

  

渴望版本:2.4秒

     

懒惰的情况:0.7秒

但是,从第二次运行开始,它们都需要 0.7秒。为什么呢?

运行时环境:

  • Scala 2.11.7
  • Java 1.8
  • OS X 10.10

2 个答案:

答案 0 :(得分:3)

省略冷战

在分析代码时,通常不会测量第一次运行/迭代,称为冷运行,因为它会导致操作系统和/或运行时环境的一些初始成本。

对于在JVM上执行的Java和Scala代码,首先执行某些指令可能需要将类和方法加载和解析到内存中,从而产生一些开销。

JVM还将在第一次迭代期间用本机指令替换例如,一些数学运算,从而加快后续迭代的执行速度。

答案 1 :(得分:1)

获取准确的基准测试非常困难 - 如果上面的代码反映了用于获取这些结果的实际代码,则不太可能获得可靠的数据。

您应该使用真正的基准测试工具,例如https://github.com/ktoso/sbt-jmh

一旦你确定性能存在显着差异,那么你就可以开始研究如何/为什么。