关于复制案例类的性能

问题描述 投票:2回答:1

我有两个案例类别:addSmalladdBigaddSmall仅包含一个字段。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要慢得多?据我了解结构共享,由于所有字段都是不可变的,因此复制对象应该非常有效,因为它只需要存储更改(“增量”)(在这种情况下仅是集合s),因此应该给定与addSmall相同的性能。

scala performance immutability jmh
1个回答
0
投票

我猜,这是因为AddBig类扩展了Foo特性,该特性具有所有这些String字段-at。看起来,在结果对象中,如果将它们与Java进行比较,它们将被声明为常规字段,而不是static字段,因此为该对象分配内存可能是复制性能降低的根本原因。希望这会有所帮助!

© www.soinside.com 2019 - 2024. All rights reserved.