我想知道从java集合到scala集合的隐式转换成本。在this doc中有几个隐含的双向转换,据说"从源类型转换为目标类型然后再返回将返回原始源对象"
我的结论是成本应该是轻微的(包装),但仍然是多少?
我问这个问题,因为我在一些scala代码中使用了java集合,在导入asScalaSet
时我会隐式转换为scala集(我确实在某些地方需要它)。但是,对于非常少的访问者(例如size()
有人知道吗?
答案 0 :(得分:2)
我决定从实际的角度回答你的问题。我使用以下简单的JMH基准来测试原始scala集合的每秒操作并转换一次(使用隐式转换)。
请查看下面的基准代码:
import org.openjdk.jmh.annotations._
import scala.collection.JavaConversions._
@State(Scope.Thread)
class WrapperBenchmark {
val unwrappedCollection = (1 to 100).toSet
val wrappedCollection: java.util.Set[Int] = (1 to 100).toSet[Int]
@Benchmark
def measureUnwrapped: Int = unwrappedCollection.size
@Benchmark
def measureWrapped: Int = wrappedCollection.size()
}
我使用sbt和sbt-jmh插件进行运行。请在下面找到结果:
[info] Benchmark Mode Cnt Score Error Units
[info] WrapperBenchmark.measureUnwrapped thrpt 200 353214968.844 ± 1534779.932 ops/s
[info] WrapperBenchmark.measureWrapped thrpt 200 284669396.241 ± 4223983.126 ops/s
所以基本上根据结果,确实存在开销。我会尝试继续我的研究,在稍后更新这个问题时提供原因。
如果您希望我为您未来的研究分享完整的sbt项目,请告诉我。
答案 1 :(得分:1)
这是使用Scala 2.13.1 CollectionConverters
import org.openjdk.jmh.annotations._
import scala.jdk.CollectionConverters._
import java.{util => ju}
@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
class So31830028 {
val size = 1000000
val scalaSet: Set[Int] = (1 to size).toSet
val javaSet: ju.Set[Int] = (1 to size).toSet.asJava
@Benchmark def scala = scalaSet.size
@Benchmark def scalaAsJava = scalaSet.asJava.size
@Benchmark def java = javaSet.size
@Benchmark def javaAsScala = javaSet.asScala.size
}
sbt "jmh:run -i 10 -wi 5 -f 2 -t 1 bench.So31830028"
给出的地方
[info] Benchmark Mode Cnt Score Error Units
[info] So31830028.java thrpt 20 356515729.840 ± 64691657.672 ops/s
[info] So31830028.javaAsScala thrpt 20 270053471.338 ± 36854051.611 ops/s
[info] So31830028.scala thrpt 20 448415156.726 ± 53674976.259 ops/s
[info] So31830028.scalaAsJava thrpt 20 211808793.234 ± 57898858.737 ops/s
实际上,这似乎是一笔不小的费用。