clojureの並列処理 デュアルコア その2

Posted by TAKAIY On 2011年8月20日土曜日 0 コメント
自宅のパソコンが壊れちゃったので、新しいノートPCを買った。
最近はいいやつが安く買えるので、思いきってCore i7のを買ってしまった。
で、前に仕事パソコンでやった並列処理の速度を測ってみた。

新PC
  Core i7 2630
  クロック 2.00GHz
  コア数 4
  MEM: 4GB

旧PC
  Core?2 Duo SL9300
  クロック 1.60GHz
  コア数 2
  MEM: 2GB

さらにi7はハイパースレッディングで仮想コアがあるのでOSからは8つのコアに見える。

処理は 2の10000乗を10000個計算して、下2桁の合計を求めるもの。

まずは単一スレッドでの実行。
コードはこれ。

(let [nums 10000]

(time

(reduce + (map (fn [x] (rem (expt 2 x) 100)) (repeat 10000 nums)))))




結果は
旧 5562 msecs
新 4251 msecs

クロックを比較すると、2.0GHzは1.6GHzの1.25倍なので所用時間が反比例するとしたら、 5562 / 1.25 = 4449 になる。 実際はもうちょっと速いけど、まあ、コア単体ではそれほど性能が上っているわけではないことがわかる。


次に、pmapを使って10000個をそれぞれ並列に処理してみる。

コード

(let [nums 10000]

(time

(reduce + (pmap (fn [x] (rem (expt 2 x) 100)) (repeat 10000 nums)))))




結果
旧 3480 msecs
新 1150 msecs

半分以下の時間になった。単一スレッドとの時間で比較しても、旧では36%減だけど、新では、73%減。

タスクマネージャの表示をキャプチャしたのが下の画像。

上は単一スレッドでの実行で、5番目だけ仕事をしてるけど、並列にすると、ちゃんと全てのコアが仕事をしているのがわかる。


また、前にも書いたとおり、上の並列処理は10000個を全部別のスレッドに割りあてていて、オーバーヘッドが大きくなってしまっている。適当なサイズに分割することで、もう少し速度が向上するはず。
以下のようにいくつかずつに分割して割り当てて実行してみた。

2分割の場合の処理がこれ。

(let [nums 10000]

(time

(reduce + (pmap #(reduce + (map (fn [x] (rem (expt 2 x) 100)) %))

(partition 5000 (repeat 10000 nums))))))



全部の結果をまとめてみた。
単位はmsec。

            旧     新

1分割 5562 4251

2分割 3092 2157

10分割 3064 1132

100分割 3099 1106

1000分割 3255 1129

10000分割 3480 1150


2コアに比べて、分割数を大くしても性能の低下が少ない感じです。
スレッド(タスク)の切りかえが高速なのかもしれませんね。

0 コメント:

コメントを投稿