Scalaが遅かったけど原因が分かった件
Project Eulerの問題44
http://projecteuler.net/problem=44
これを解こうとして、以下のようなコードを書いた
https://gist.github.com/ponkotuy/5791300
のだが、Scala版が遅くて困っている件。どれぐらいかというと、HaswellのCPUで、Dは秒も掛かってないが、Scalaは10秒待っても終わる気配が無いので最後までやったことが無いレベル。
Profileを取る
遅いだけでなくProfileもナゾで、
1 97.58% 97.58% 2419 300545 scala.collection.immutable.Range.foreach
なんかforeachで時間食ってるとか言われる。
TRACEを見てみると、
TRACE 300545: scala.collection.immutable.Range.foreach(Range.scala:141) scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:721) Prob44_2$$anonfun$3.apply(Prob44_2.scala:21) Prob44_2$$anonfun$3.apply(Prob44_2.scala:20) scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251) scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251) scala.collection.immutable.Range.foreach(Range.scala:141) scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251) scala.collection.AbstractTraversable.flatMap(Traversable.scala:105) Prob44_2$.main(Prob44_2.scala:20) Prob44_2.main(Prob44_2.scala:Unknown line) sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:Unknown line) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:601) scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:71) scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31) scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:139) scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:71) scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:139) scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:28) scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:45) scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:35) scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:45) scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:74) scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96) scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105) scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala:Unknown line)
foreachが遅いの?
と思って試してみたコード
import scala.compat.Platform object RangeTime { def timer(f: Unit => Unit): Long = { val before = Platform.currentTime f() return Platform.currentTime - before } def main(args: Array[String]) { val result = timer { _ => var long = 0L for { i <- 1 to 1000 j <- (i + 1) to 1000 if (i%2 != 0 && j%2 != 0) } { long += i + j } println(long) } println(result) } }
結論から言うと先程の結果が出てくるほど遅くはなかった。瞬間で終わる。
細い設定とか
hprofを取るときの設定は、-agentlib:hprof=cpu=samples,depth=30 -XX:+HeapDumpOnOutOfMemoryError
あとScalaのバージョンは2.10.2
原因
お前List(双方向リスト)にIndexアクセスしてんじゃねーよ!
val pentagonals = Stream.from(0).map(pentagonal).takeWhile(_ < (Int.MaxValue >> 2)).toList ... val pj = pentagonals(j) val pk = pentagonals(k)
toArrayになおしたら問題なく終わりました…。
ただしhprofさんが情報出してくれなかった点に関してはまだ調査中…。