为什么 Scala 的 for 循环比处理不同对象序列的 while 循环快得多?

Why are Scala for loops so much faster than while loops for processing a sequence of distinct objects?

我最近读到 post 一篇关于 运行ge 整数的 for 循环比相应的 while 循环慢的文章,这是真的,但我想看看是否同样适用于迭代在现有序列上,惊讶地发现完全相反的结果。

首先,我使用以下函数进行计时:

def time[A](f: => A) = {
    val s = System.nanoTime
    val ret = f
    println("time: " + (System.nanoTime - s) / 1e6 + "ms")
    ret
}

我正在使用一个简单的整数序列:

val seq = List.range(0, 10000)

(我还尝试通过其他几种方式创建此序列,以防访问此序列的方式影响 运行 时间。使用 Range 类型肯定会影响。这应该确保每个项目在序列中是一个独立的对象。)

我运行以下:

time {
  for(item <- seq) {
    println(item)
  }
}

time {
  var i = 0
  while(i < seq.size) {
    println(seq(i))
    i += 1
  }
}

我打印了结果,以确保我们实际上访问了两个循环中的值。第一个代码片段 运行s 在我的机器上平均 33 ms。第二个平均需要 305 毫秒.

我尝试将可变变量 i 添加到 for 循环中,但它只增加了几毫秒。正如预期的那样,map 函数获得与 for 循环相似的性能。无论出于何种原因,如果我使用数组(将上面定义的 seq 转换为 seq.toArray),这似乎不会发生。在这种情况下,for 循环需要 90 毫秒,而 while 循环需要 40 毫秒。

造成这种主要性能差异的原因是什么?

原因是:复杂性。 seq(i)List 的 Θ(i),这意味着您的整个循环需要二次方时间。然而,foreach 方法是线性的。

如果使用 -optimize 编译,for 循环版本可能会更快,因为 List.foreach 应该是内联的,消除了 lambda 的成本。