少し前に、可変変数を新しい値で(ただし、新しいオブジェクトを作成せずに)更新する方法が高速であるかどうかを判断するためのコードを作成しました。1つの方法は一時的な値を使用し、余分なコピーがあり、他の方法は使用しません。
コードサンプル#1-再割り当てあり
class Test(var x: Float, var y: Float) {
@inline final def :=(x: Float, y: Float) = {
this.x = x
this.y = y
}
//...
@inline final def :=(o: Test) = { //reassign from arg "o"
x = o.x
y = o.y
}
//...
}
object Benchmark {
//...
val tmp = new Test(0, 0)
@inline final def calc_something_for_reassign(a: Float, b: Float) = {
tmp := (a, b)
tmp.something_m //this is a simple method that changes the object
tmp
}
//...
}
コードサンプル#2-再割り当てなし
class Test(var x: Float, var y: Float) {
@inline final def := (x: Float, y: Float) = //it's the same as in sample #1
//...
@inline final def := (of: (Test) => Unit) = { //apply mutating function "of"
of(this)
}
//...
}
object Benchmark {
//...
@inline final def calc_something_for_forwarding(a: Float, b: Float) = {
(result: Test) => {
result := (a, b)
result.something_m
}
}
}
完全なコードはここにあります:http://ideone.com/A62Ts
私のPC(scalaコンパイラv。2.8、jre7)では、結果は期待どおりに見えます。
reassignment: 0.046sec; Result:42.0, 3.0
forwarding: 0.007sec; Result:42.0, 3.0
forwarding: 0.006sec; Result:42.0, 3.0
reassignment: 0.044sec; Result:42.0, 3.0
(はい、テストの長さを増やしても、比率は同じであり、コンパイラーのオプションは重要ではありません。)
このテストはAndroidOS2.3.4を搭載した携帯電話で実行しましたが、勝者は同じです。しかし、ご覧のとおり、Ideone.comでは逆のことが起こり、2番目の方法ははるかに遅くなります。では、実際にそこで何が起こっているのか説明できますか?そして、Scalaコンパイラの(これら2つの)バージョンのどちらが正しく機能していますか?それはscala-2.9.1のバグですか?
更新:scala 2.9では、テストは次のように出力します(何度も試しましたが、何もあまり変化しません):
reassignment: 0.047sec; Result:42.0, 3.0
forwarding: 0.032sec; Result:42.0, 3.0
forwarding: 0.219sec; Result:42.0, 3.0
reassignment: 0.045sec; Result:42.0, 3.0
また、サイクル数に関係なく、3回目の実行は他のすべての実行よりも長くなります。それはGCを引き起こす可能性がありますか?または、なぜ他にそのような奇妙なことが起こる可能性がありますか?代わりに、b、b、a、b、b、aの順に呼び出すと、そのような奇妙なピークはありません。
println(Benchmark.run_b(Int.MaxValue/10))
println(Benchmark.run_b(Int.MaxValue/10))
println(Benchmark.run_a(Int.MaxValue/10))
println(Benchmark.run_b(Int.MaxValue/10))
println(Benchmark.run_b(Int.MaxValue/10))
println(Benchmark.run_a(Int.MaxValue/10))
Scala 2.8(安定版)の結果:
forwarding: 0.012sec; Result:42.0, 3.0
forwarding: 0.012sec; Result:42.0, 3.0
reassignment: 0.347sec; Result:42.0, 3.0
forwarding: 0.011sec; Result:42.0, 3.0
forwarding: 0.005sec; Result:42.0, 3.0
reassignment: 0.333sec; Result:42.0, 3.0
Scala 2.9(安定版)の結果:
forwarding: 0.184sec; Result:42.0, 3.0
forwarding: 0.179sec; Result:42.0, 3.0
reassignment: 0.354sec; Result:42.0, 3.0
forwarding: 0.17sec; Result:42.0, 3.0
forwarding: 0.169sec; Result:42.0, 3.0
reassignment: 0.342sec; Result:42.0, 3.0
ただし、scala 2.9で再割り当てを行う方法は、scala 2.8と同じくらい長いですが、高速の方法は、scala 2.9では約10倍遅くなります(ただし、低速の方法よりも約2倍高速です)。それで、元の質問はまだ生きています、なぜそれがscala2.9でとても遅いのですか?