У меня есть два класса дел: addSmall
и addBig
. addSmall
содержит только одно поле. addBig
содержит несколько полей.
case class AddSmall(set: Set[Int] = Set.empty[Int]) {
def add(e: Int) = copy(set + e)
}
case class AddBig(set: Set[Int] = Set.empty[Int]) extends Foo {
def add(e: Int) = copy(set + e)
}
trait Foo {
val a = "a"; val b = "b"; val c = "c"; val d = "d"; val e = "e"
val f = "f"; val g = "g"; val h = "h"; val i = "i"; val j = "j"
val k = "k"; val l = "l"; val m = "m"; val n = "n"; val o = "o"
val p = "p"; val q = "q"; val r = "r"; val s = "s"; val t = "t"
}
Быстрый бенчмарк с использованием JMH показывает, что копирование addBig
объектов намного более обширно, даже если я изменяю только одно поле ..
import java.util.concurrent.TimeUnit
import org.openjdk.jmh.annotations._
@State(Scope.Benchmark)
class AddState {
var elem: Int = _
var addSmall: AddSmall = _
var addBig: AddBig = _
@Setup(Level.Trial)
def setup(): Unit = {
addSmall = AddSmall()
addBig = AddBig()
elem = 1
}
}
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Array(Mode.Throughput))
class SetBenchmark {
@Benchmark
def addSmall(state: AddState): AddSmall = {
state.addSmall.add(state.elem)
}
@Benchmark
def addBig(state: AddState): AddBig = {
state.addBig.add(state.elem)
}
}
И результаты показывают, что копирование addBig
более чем в 10 раз медленнее, чем копирование addSmall
!
> jmh:run -i 5 -wi 5 -f1 -t1
[info] Benchmark Mode Cnt Score Error Units
[info] LocalBenchmarks.Set.SetBenchmark.addBig thrpt 5 10732.569 ± 349.577 ops/ms
[info] LocalBenchmarks.Set.SetBenchmark.addSmall thrpt 5 126711.722 ± 10538.611 ops/ms
Почему копирование объекта намного медленнее для addBig
? As Насколько я понимаю структурное совместное использование, поскольку все поля являются неизменяемыми, копирование объекта должно быть очень эффективным, поскольку для него нужно только хранить изменения («дельта»), которые в данном случае являются только набором s
, и, следовательно, должны давать одинаковые производительность как addSmall
.
РЕДАКТИРОВАТЬ: та же проблема производительности возникает, когда состояние является частью класса дела.
case class AddBig(set: Set[Int] = Set.empty[Int], a: String = "a", b: String = "b", ...) {
def add(e: Int) = copy(set + e)
}