Control.Parallel の par を使うと第一引数を別スレッドで評価してくれる(かも).ということで,試した.
import Control.Parallel homP op f x = h x where h [a] = f a h (a:x) = fa `par` (hx `seq` (fa `op` hx)) where fa = f a hx = h x mapP f = homP (++) (\x->[f x]) chunk n [] = [] chunk n x = take n x:chunk n (drop n x) split p x = chunk (div (length x + p - 1) p) x mapS f dxs = mapP (map f) dxs reduceS op dxs = homP op (foldl1 op) dxs main = print $ reduceS(+) $ mapS f $ split 32 [1..10000] f n = fib 16 fib 0 = 1 fib 1 = 1 fib n = fib (n - 1) + fib (n - 2)
基本,split でチャンクに切り分けて,homP で各チャンクに対する計算を並列評価する.
par の型は a -> b -> b で,デフォルトだと最初の引数を完全に無視する.んで,コンパイルというかリンク時に -threaded をつけてやると別スレッドでの並列評価を試みるコードになってくれるらしい.あと,実行時に +RST -N2 とかやって, N オプションで生成するネイティブスレッドの数を指定する.
とりあえず上のコードを デュアルコアで動かしたら 2.5 秒が 1.5 秒になる程度の効果が現れた.確かに並列で評価してくれているらしい.
ちなみに,
main = print $ sum $ concat $ mapS f $ split 32 [1..10000]
としてあげると並列計算の効果が全く現れない.sum の計算が concat の結果を頭から消費していく形なので,前のチャンクの結果が sum で消費しつくされてからしか次のチャンクの評価が起こらない.なので,mapS f での各チャンクに対する map f の評価が逐次的にしか起きてくれず,並列計算にならない.と思う.とりあえず遅延評価があると思ったより面倒だなぁ.
- Newer: AWK - はじめ