如果我有一个通用参数,我通过与Int
等基元的模式匹配来解析该参数,那么自动装箱是否比使用自定义包装类型更便宜?例如
def test[A](x: A): Int = x match {
case i: Int => i
case _ => -1
}
对比
case class NumChannels(value: Int)
def test[A](x: A): Int = x match {
case n: NumChannels => n.value
case _ => -1
}
第一种方法是否提供任何性能优势?如果该方法使用 Any
来代替,这种情况是否相同:
def test(x: Any): Int = ...
?
最佳答案
如果您查看 javap
的输出(仅不同的部分):
- 使用
Int
的版本:
10: invokestatic #17 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I 13: istore_3 14: iload_3
- 使用
NumChannels
的版本:
10: checkcast #12 // class app/benchmark/scala/benchmark3b/NumChannels 13: astore_3 14: aload_3 15: invokevirtual #16 // Method app/benchmark/scala/benchmark3b/NumChannels.value:()I
人们可能会认为第一个版本应该更快。使用 Any
的第三个版本的结果与第一个版本相同。
然而,使用 JMH 的微基准测试没有显示出真正的差异:
Benchmark Mode Samples Mean Mean error Units
a.b.s.benchmark3a.Benchmark3a.run thrpt 5 42,352 0,480 ops/ms
a.b.s.benchmark3b.Benchmark3b.run thrpt 5 42,793 1,439 ops/ms
使用 Oracle JDK 1.8、Scala 2.10.3、Linux 32 位。
第一个基准:
@State(Scope.Benchmark)
object BenchmarkState {
final val n = 10000
val input =
Array.range(0, n).map {
n =>
if (n % 2 == 0) {
n
} else {
"" + n
}
}
}
class Benchmark3a {
def test[A](x: A): Int = x match {
case i: Int => i
case _ => -1
}
@GenerateMicroBenchmark
def run() = {
var sum = 0
var i = 0
while (i < BenchmarkState.n) {
sum += test(BenchmarkState.input(i))
i +=1
}
sum
}
}
第二个基准
case class NumChannels(value: Int)
@State(Scope.Benchmark)
object BenchmarkState {
final val n = 10000
val input =
Array.range(0, n).map {
n =>
if (n % 2 == 0) {
NumChannels(n)
} else {
"" + n
}
}
}
class Benchmark3b {
def test[A](x: A): Int = x match {
case n: NumChannels => n.value
case _ => -1
}
@GenerateMicroBenchmark
def run() = {
var sum = 0
var i = 0
while (i < BenchmarkState.n) {
sum += test(BenchmarkState.input(i))
i +=1
}
sum
}
}
在之前的版本中,我使用了 Seq
以及方法 map
和 sum
,两个版本的性能相当,但它们只达到了 4 左右操作/毫秒。
即使使用 Array
和 while
也没有揭示出真正的区别。
所以我想说这个(独立的)API 设计决策不会影响性能。
资源
- How can I use JMH for Scala benchmarks together with sbt? (我已使用所选答案中描述的设置)
关于scala - 自动装箱是否比自定义包装器类型表现更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24799706/