Я создаю метод Scala для добавления элементов в ArrayBuffer
.Я думаю о 2 подходах:
def addToArrayBuffer(b: ArrayBuffer[Int])
def addToArrayBuffer(cb: Int => Unit)
Первый подход - это метод, который получает коллекцию и добавляет элементывнутрь.Второй подход - это метод, который получает обратный вызов cb
и вызывает этот обратный вызов для каждого элемента, который я хочу добавить в коллекцию.
Второй подход является более гибким, поскольку я могу преобразовывать / фильтровать элементы перед добавлением их в коллекцию.
К сожалению, второй подход медленнее (72 операции / с против 57 операций / с):
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 не может оптимизировать обратный вызов и достичь той же скорости, что ипрямое добавление в коллекцию?И как мне улучшить скорость?
Я использую java
версию 1.8.0_162
на Mac.Вот источник бенчмарка:
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)
}
}