Haskell并行化和线程中的严格评估..?

时间:2018-03-16 12:23:21

标签: haskell parallel-processing

我试图从给定的数字列表中找到素数。 到目前为止,我有一段有用的代码,但如果我取消注释某些行并评论其他一些代码,我认为速度没有任何差别。 我几乎可以肯定我必须在单独的线程中强制进行评估,因为我认为我启动了线程但是由于懒惰而没有在那里评估代码。但我找不到强制评估的方法。我的工作基于例子here。所以我创建了函数parMapstrMap,它们是并行映射和严格[并行]映射。在parMap中有2行注释,所以如果你取消注释它们,并注释掉当前没有注释的其他4行,那么,你不能注意速度的任何差异,尽管它应该是非平行的并且慢一些然后。我现在也忽略了main函数中的程序参数。

所以基本上我的问题是 - 是否有可能实现,对于给予parMap的列表中的每个数字,会产生一个新线程,所以一切都运行得更快?

这里是代码:

module W7T5
(
  main
) where

import Control.Concurrent
import Control.Parallel (par, pseq)
import System.Environment

main = do
  args' <- getArgs
  let
--    args = map (\x -> read x :: Int) args'
    args = [2000000..2000200]
    tfPrime = parMap isPrime' args
--    tfPrime = strMap isPrime' args
    argsNtf = zip args tfPrime
    primes' = filter (\(num, tfPrime) -> tfPrime) argsNtf
    primes = map fst primes'
  putStrLn ("Init list: " ++ show args)
  putStrLn ("Primes   : " ++ show primes)

-- Map in parallel
parMap :: NFData a => (a -> b) -> [a] -> [b]
parMap _ [] =
  []
--parMap f (x:xs) = -- sadly without any parallelisation it's not slower
--  (f x) :parMap f xs
parMap f (x:xs) =
  par r (r:parMap f xs)
  where
    r = f x

-- Map in parallel strictly
strMap :: (a -> b) -> [a] -> [b]
strMap f xs =
  forceList xs `seq` map f xs

forceList :: [a] -> ()
forceList (x:xs) =
  xs `pseq` forceList xs
forceList _ =
  ()

isPrime' :: Int -> Bool
isPrime' 0 = True
isPrime' 1 = True
isPrime' 2 = True
isPrime' num =
  all (/=0) [mod num x | x <- [2..(num-1)]]

您可以使用

运行程序
runhaskell W7T5.hs 1 2 3 4

1 个答案:

答案 0 :(得分:0)

对于速度(这是并行点),应该编译Haskell程序(使用ghc)而不是解释(使用runghc)。我不知道如何实际使用runghc多线程,如果可能的话。

ghc W7T5 -threaded -with-rts -N2
./W7T5

parMap实现是不正确的:计算(r : parMap f xs)立即返回并且只是thunks尾巴,它只会在需要时被引发(但到那时它也会被引发)晚了)。下面的一个会在它们出现之前激发头部和尾部,所以当调用者看到构造函数时,列表的其余部分将在后台进行评估。

parMap :: (a -> b) -> [a] -> [b]
parMap f [] = []
parMap f (x : xs) = rs `par` r `par` (r : rs)
  where
    r = f x
    rs = parMap f xs

编译程序时,您可能看不到与解释程序相同的缓冲行为,因为可执行文件默认使用行缓冲。可以使用System.IO.hSetBuffering

关闭缓冲
import System.IO

main = do
  hSetBuffering stdout NoBuffering
  ...