我想要一个为parMap rpar
列表所做的向量做的函数。这就是我所拥有的:
import Data.Vector
import Control.Parallel.Strategies
parMapVec :: (a -> b) -> Vector a -> Vector b
parMapVec f = map (runEval . rpar . f)
我无法完全推断出这将如何或为何会起作用。
另一个解决方案可能是让Vector
成为Traversable
的一个实例,然后使用parTraversable
,但这似乎只是为了得到像parMap rpar
这样的东西。
答案 0 :(得分:1)
Vector
确实是Taversable
的一个实例。我认为这不是因为它没有列为Data.Traversable page.
知道了这一点,我进行了一些测试:
import Control.Parallel.Strategies
import Data.Vector as V
import Data.Maybe
parMapVec :: (a -> b) -> Vector a -> Vector b
parMapVec f v = runEval $ evalTraversable rpar $ V.map f v
range :: Integer -> Integer -> Vector Integer
range x y
| x == y = x `cons` empty
| x < y = x `cons` (range (x + 1) y)
| x > y = (range x (y + 1)) `snoc` y
fac :: Integer -> Integer
fac n
| n < 2 = 1
| otherwise = n * (fac $ n - 1)
main :: IO ()
main = do
let result = runEval $ do
let calc = parMapVec fac $ 80000 `range` 80007
rseq calc
return calc
putStrLn $ show result
我使用ghc --make ParVectorTest.hs -threaded -rtsopts
对其进行了编译,并使用./ParVectorTest -s
运行并找到了
SPARKS: 8 (7 converted, 0 overflowed, 0 dud, 0 GC'd, 1 fizzled)
INIT time 0.001s ( 0.001s elapsed)
MUT time 5.460s ( 5.447s elapsed)
GC time 15.916s ( 15.893s elapsed)
EXIT time 0.000s ( 0.000s elapsed)
Total time 21.380s ( 21.342s elapsed)
哪个好,除了我看到我的系统监视器上的进程执行,并看到核心是,而不是同时计算一个阶乘,在计算之间进行权衡。
这很令人担忧,所以我做了一个测试,其中main
以下列方式被修改:
main = do
let result = runEval $ do
let calc = parMap rpar fac [80000..80007]
rseq calc
return calc
putStrLn $ show result
我编译并以同样的方式运行以找到:
SPARKS: 16 (14 converted, 0 overflowed, 0 dud, 1 GC'd, 1 fizzled)
INIT time 0.001s ( 0.001s elapsed)
MUT time 5.412s ( 5.418s elapsed)
GC time 18.583s ( 18.537s elapsed)
EXIT time 0.001s ( 0.000s elapsed)
Total time 23.999s ( 23.957s elapsed)
我不确定为什么会有16个火花而不是8火花,但我认为除此之外还有。此版本还演示了在处理器之间传递的计算的相同行为,而不是实际并行执行。
所以,我有一个parMap rpar
版本的矢量稍微快一些,尽管程序使用列表和使用矢量完全并行运行的程序都是关注的事实。
编辑:我应该补充一点,我使用原始版本的parMapVec
运行相同的测试并且所有火花都失败了,尽管我无法解释原因。