为什么 JVM 不优化简单的回调(在 Scala 中)?

Why JVM doesn't optimize simple callback (in Scala)?

我正在创建 Scala 方法以将元素添加到 ArrayBuffer。我正在考虑两种方法:

第一种方法是获取集合并将元素添加到其中的方法。第二种方法是获取回调 cb 并为我要添加到集合中的每个元素调用此回调的方法。

第二种方法更灵活,因为我可以 transform/filter 个元素,然后再将它们添加到集合中。

不幸的是,第二种方法较慢(72 ops/s vs 57 ops/s):

Benchmark                                        Mode  Cnt   Score    Error  Units
TestBenchmark.addToArrayBufferDirectly          thrpt    9  72.808 ? 13.394  ops/s
TestBenchmark.addToArrayBufferViaCallback       thrpt    9  57.786 ?  3.532  ops/s

我的问题是为什么JVM无法优化回调并达到与直接添加到集合相同的速度?我怎样才能提高速度?

我在 Mac 上使用 java 版本 1.8.0_162。这是基准的来源:

package bench

import org.openjdk.jmh.annotations.{Benchmark, Fork, Measurement, Scope, State, Warmup}
import org.openjdk.jmh.infra.Blackhole

import scala.collection.mutable.ArrayBuffer

@State(Scope.Thread)
@Warmup(iterations = 5)
@Measurement(iterations = 3)
@Fork(3)
class TestBenchmark {

  val size = 1000000

  @Benchmark
  def addToArrayBufferDirectly(blackhole: Blackhole) = {
    def addToArrayBuffer(b: ArrayBuffer[Int]) = {
      var i = 0
      while (i < size) {
        b.append(i)
        i += 1
      }
    }

    val ab = new ArrayBuffer[Int](size)
    addToArrayBuffer(ab)
    blackhole.consume(ab)
  }

  @Benchmark
  def addToArrayBufferViaCallback(blackhole: Blackhole) = {
    def addToArrayBuffer(cb: Int => Unit) = {
      var i = 0
      while (i < size) {
        cb(i)
        i += 1
      }
    }

    val ab = new ArrayBuffer[Int](size)
    addToArrayBuffer(i => ab.append(i))
    blackhole.consume(ab)
  }
}

Scala 编译器可以使用 flags 对其进行优化

scalacOptions ++= Seq(
  "-opt-inline-from:bench.**",
  "-opt:l:inline"
)

无需更改代码。有关 Scala 内联的更多信息:https://www.lightbend.com/blog/scala-inliner-optimizer