話の発端はこんな感じ↓
#scala 合算する方法って、他にどんなのがあるだろう… http://www.ne.jp/asahi/hishidama/home/tech/scala/sample/sum.html
そういえばparallel collection使えば速くなるんじゃ!
試したんですが上手く動かなくて http://www.ne.jp/asahi/hishidama/home/tech/scala/collection/par.html #scala RT @xuwei_k: そういえばparallel collection使えば速くなるんじゃ!
というわけで、気になったのでやってみた↓
Welcome to Scala version 2.9.0.r24350-b20110228020058 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_24). Type in expressions to have them evaluated. Type :help for more information. scala> scala.collection.parallel.availableProcessors // CPUは core i5だから、実際はコア数 2 ? res0: Int = 4 scala> def benchmark(times: Int)(f: =>Any) = new scala.testing.Benchmark{ def run = f }.runBenchmark(times) benchmark: (times: Int)(f: => Any)List[Long] scala> implicit def benchmark2report(list:List[Long]) = new { val average = (list.sum - list.max - list.min).toDouble / (list.size-2) } benchmark2report: (list: List[Long])java.lang.Object{val average: Double} scala> def test(listSize:Int){ | println("--------------" + listSize + "---------------") | val normal = 1L to listSize toList //普通のListつくる | val parSeq = normal toParSeq //要素が同じparalell版をつくる | val normalResult = benchmark(5)( normal.reduceLeft(_ + _) ) | //reduceというのが、paralellなcollectionにしかないメソッドで、 | //内部でスレッド生成し分割して処理してるらしい | val parSeqResult = benchmark(5)( parSeq.reduce(_ + _) ) | println( normalResult , parSeqResult , parSeqResult.average / normalResult.average ) | } test: (listSize: Int)Unit scala> 2000000 to 20000000 by 2000000 foreach test --------------2000000--------------- (List(334, 43, 45, 47, 44),List(28, 23, 22, 20, 20),0.47794117647058826) --------------4000000--------------- (List(196, 70, 98, 76, 71),List(45, 45, 46, 44, 45),0.5510204081632653) --------------6000000--------------- (List(1330, 159, 147, 161, 140),List(95, 74, 81, 99, 97),0.5845824411134904) --------------8000000--------------- (List(722, 166, 168, 170, 159),List(107, 115, 114, 114, 111),0.6726190476190477) --------------10000000--------------- (List(1104, 192, 202, 193, 197),List(132, 131, 129, 130, 125),0.6587837837837838) --------------12000000--------------- (List(3089, 255, 274, 260, 233),List(164, 165, 165, 166, 159),0.6261089987325729) --------------14000000--------------- (List(1365, 264, 265, 323, 249),List(176, 178, 180, 171, 171),0.6161971830985915) --------------16000000--------------- (List(1726, 330, 300, 288, 292),List(220, 204, 219, 203, 209),0.6854663774403471) --------------18000000--------------- (List(2147, 343, 335, 333, 326),List(231, 241, 228, 252, 245),0.7091988130563798) --------------20000000--------------- (List(4329, 621, 549, 483, 474),List(322, 251, 258, 256, 255),0.46521476104053233)
パソコンのスペックは
- Core i5-450M
- メモリ 4GB
- ubuntu10.10
reduceとreduceLeftについて、
- 要素数を200万から2000万まで200万きざみで変更
- それぞれ5回ずつ計測して、最速と最遅を除いた3回分の平均を計算
しました
普通のListに対してreduceLeftするより、parallel collectionのほうが、だいたい60%くらいの時間に短縮されてる。
もっとコア数が4とか8個ぐらいあるマシンでやってみたい・・・
*1: REPLのデフォルトの256Mだとヒープ足りなくなる