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



我试图从给定的数字列表中找到质数。 到目前为止,我有一段有效的代码,但是如果我取消注释某些行并注释其他一些行,则看不到速度有任何差异。 我几乎可以肯定我必须在单独的线程中强制评估,因为我认为我启动了线程,但由于懒惰而没有在那里评估代码。但我找不到一种方法来强制这种评估。我是根据这里的例子工作的。所以我做了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

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

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

parMap实现是不正确的:计算(r : parMap f xs)立即返回,只是扔掉尾巴,只有在需要时才会被触发(但到那时为时已晚)。下面的那个在组成它们之前会激发头部和尾部,因此当调用者看到构造函数时,列表的其余部分正在后台进行评估。

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
...

最新更新