Chr*_*oth 33 performance scala implicit-conversion
在Scala中,使用隐式类型转换来增强类的功能与其他可能的实现选择相比,是否存在显着的CPU或内存影响?
例如,考虑一个愚蠢的字符串操作函数.此实现使用字符串连接:
object Funky {
def main(args: Array[String]) {
args foreach(arg => println("Funky " + arg))
}
}
Run Code Online (Sandbox Code Playgroud)
此实现通过使用隐式类型转换隐藏成员方法背后的串联:
class FunkyString(str: String) {
def funkify() = "Funky " + str
}
object ImplicitFunky {
implicit def asFunkyString(str: String) = new FunkyString(str)
def main(args: Array[String]) {
args foreach(arg => println(arg.funkify()))
}
}
Run Code Online (Sandbox Code Playgroud)
两者都做同样的事情:
scala> Funky.main(Array("Cold Medina", "Town", "Drummer"))
Funky Cold Medina
Funky Town
Funky Drummer
scala> ImplicitFunky.main(Array("Cold Medina", "Town", "Drummer"))
Funky Cold Medina
Funky Town
Funky Drummer
Run Code Online (Sandbox Code Playgroud)
有任何性能差异吗?一些具体的考虑因素:
Scala是否内联对asFunkyString方法的隐式调用?
Scala实际上是为每个arg创建一个新的包装器FunkyString对象,还是可以优化掉额外的对象分配?
假设FunkyString有3种不同的方法(funkify1,funkify2和funkify3),并且foreach的主体连续调用每个方法:
println(arg.funkify1())
println(arg.funkify2())
println(arg.funkify3())
Run Code Online (Sandbox Code Playgroud)
Scala会重复转换3次,还是会优化掉冗余转换并为每次循环迭代执行一次?
假设我明确地在另一个变量中捕获转换,如下所示:
val fs = asFunkyString(arg)
println(fs.funkify1())
println(fs.funkify2())
println(fs.funkify3())
Run Code Online (Sandbox Code Playgroud)
这会改变这种情况吗?
实际上,隐式转换的广泛使用是潜在的性能问题,还是通常无害?
par*_*tic 20
我尝试使用优秀的Scala-Benchmark-Template设置微基准测试.
编写一个有意义的(非优化的JIT)基准测试很难测试隐式转换,因此我不得不增加一些开销.
这是代码:
class FunkyBench extends SimpleScalaBenchmark {
val N = 10000
def timeDirect( reps: Int ) = repeat(reps) {
var strs = List[String]()
var s = "a"
for( i <- 0 until N ) {
s += "a"
strs ::= "Funky " + s
}
strs
}
def timeImplicit( reps: Int ) = repeat(reps) {
import Funky._
var strs = List[String]()
var s = "a"
for( i <- 0 until N ) {
s += "a"
strs ::= s.funkify
}
strs
}
}
Run Code Online (Sandbox Code Playgroud)
以下是结果:
[info] benchmark ms linear runtime
[info] Direct 308 =============================
[info] Implicit 309 ==============================
Run Code Online (Sandbox Code Playgroud)
我的结论:在任何非常重要的代码中,隐式转换(对象创建)的影响是不可测量的.
编辑:我使用scala 2.9.0和java 1.6.0_24(在服务器模式下)