gpt4 book ai didi

scala - 为什么Scala中独立代码块的执行时间依赖于执行顺序?

转载 作者:行者123 更新时间:2023-12-03 01:18:51 24 4
gpt4 key购买 nike

我有一个用 Scala 编写的程序。我想测量不同独立代码块的执行时间。当我以明显的方式执行此操作时(即在每个 block 之前和之后插入System.nanoTime()),我观察到执行时间取决于 block 的顺序。前一些 block 总是比其他 block 花费更多的时间。

我创建了一个重现此行为的简约示例。所有代码块都是相同的并调用 hashCode()为简单起见,为整数数组。

package experiments

import scala.util.Random

/**
* Measuring execution time of a code block
*
* Minimalistic example
*/
object CodeBlockMeasurement {

def main(args: Array[String]): Unit = {
val numRecords = args(0).toInt
// number of independent measurements
val iterations = args(1).toInt

// Changes results a little bit, but not too much
// val records2 = Array.fill[Int](1)(0)
// records2.foreach(x => {})

for (_ <- 1 to iterations) {
measure(numRecords)
}
}

def measure(numRecords: Int): Unit = {
// using a new array every time
val records = Array.fill[Int](numRecords)(new Random().nextInt())
// block of code to be measured
def doSomething(): Unit = {
records.foreach(k => k.hashCode())
}
// measure execution time of the code-block
elapsedTime(doSomething(), "HashCodeExperiment")
}

def elapsedTime(block: => Unit, name: String): Unit = {
val t0 = System.nanoTime()
val result = block
val t1 = System.nanoTime()
// print out elapsed time in milliseconds
println(s"$name took ${(t1 - t0).toDouble / 1000000} ms")
}
}

使用 numRecords = 100000 运行程序后和iterations = 10 ,我的控制台如下所示:

HashCodeExperiment took 14.630283 ms
HashCodeExperiment took 7.125693 ms
HashCodeExperiment took 0.368151 ms
HashCodeExperiment took 0.431628 ms
HashCodeExperiment took 0.086455 ms
HashCodeExperiment took 0.056458 ms
HashCodeExperiment took 0.055138 ms
HashCodeExperiment took 0.062997 ms
HashCodeExperiment took 0.063736 ms
HashCodeExperiment took 0.056682 ms

有人能解释一下这是为什么吗?不应该都一样吗?哪个是真正的执行时间?

非常感谢,
彼得

Environment parameters:
OS: ubuntu 14.04 LTS (64 bit)
IDE: IntelliJ IDEA 2016.1.1 (IU-145.597)
Scala: 2.11.7

最佳答案

这是Java的JIT最初执行纯字节码,但一段时间后(Oracle JVM 默认情况下有 1.5k/10k 次调用,请参阅 -XX:CompileThreshold ),优化开始处理实际执行的 native 代码,这通常会导致相当显着的性能改进。

正如 Ivan 提到的,还有中间字节码/ native 代码的缓存以及涉及的各种其他技术,其中最重要的技术之一是垃圾收集器本身,它会导致个体结果出现更大的差异。根据代码分配新对象的数量,每当 GC 发生时,这绝对会降低性能,但这是一个单独的问题。

要在微基准测试时消除此类异常结果,建议您对操作的多次迭代进行基准测试,并丢弃底部和顶部 5..10% 的结果,并根据剩余样本进行性能估计。

关于scala - 为什么Scala中独立代码块的执行时间依赖于执行顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37049363/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com