我有两个案例类:
使用JMH进行快速基准测试,结果表明即使我只更改一个字段,复制
结果表明,复制
为什么对于
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
比复制addSmall
慢10倍以上!> 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
,复制对象会更慢?据我所知,由于所有字段都是不可变的,因此根据结构共享的原理,复制对象应该非常高效,因为它只需存储更改("delta"),在这种情况下只有设置s
,因此应该与addSmall
具有相同的性能。
编辑:当状态是案例类的一部分时,也会出现相同的性能问题。
case class AddBig(set: Set[Int] = Set.empty[Int], a: String = "a", b: String = "b", ...) {
def add(e: Int) = copy(set + e)
}