我试图理解并行策略。我认为我理解了每个组合器的作用,但每次尝试在多于1个核心的情况下使用它们时,程序都会明显减慢。
例如,之前我尝试从约700个文档中计算直方图(以及唯一单词)。我认为使用文件级细粒度就可以了。使用 -N4
时,我得到了1.70的工作平衡。然而,使用 -N1
比使用 -N4
快一半的时间。我不确定问题是什么,但我想知道如何决定何时/何处/如何并行化并获得一些了解。如何进行并行化以使速度随着内核数目的增加而增加,而不是减少?
import Data.Map (Map)
import qualified Data.Map as M
import System.Directory
import Control.Applicative
import Data.Vector (Vector)
import qualified Data.Vector as V
import qualified Data.Text as T
import qualified Data.Text.IO as TI
import Data.Text (Text)
import System.FilePath ((</>))
import Control.Parallel.Strategies
import qualified Data.Set as S
import Data.Set (Set)
import GHC.Conc (pseq, numCapabilities)
import Data.List (foldl')
mapReduce stratm m stratr r xs = let
mapped = parMap stratm m xs
reduced = r mapped `using` stratr
in mapped `pseq` reduced
type Histogram = Map Text Int
rootDir = "/home/masse/Documents/text_conversion/"
finnishStop = ["minä", "sinä", "hän", "kuitenkin", "jälkeen", "mukaanlukien", "koska", "mutta", "jos", "kuitenkin", "kun", "kunnes", "sanoo", "sanoi", "sanoa", "miksi", "vielä", "sinun"]
englishStop = ["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]
isStopWord :: Text -> Bool
isStopWord x = x `elem` (finnishStop ++ englishStop)
textFiles :: IO [FilePath]
textFiles = map (rootDir </>) . filter (not . meta) <$> getDirectoryContents rootDir
where meta "." = True
meta ".." = True
meta _ = False
histogram :: Text -> Histogram
histogram = foldr (\k -> M.insertWith' (+) k 1) M.empty . filter (not . isStopWord) . T.words
wordList = do
files <- mapM TI.readFile =<< textFiles
return $ mapReduce rseq histogram rseq reduce files
where
reduce = M.unions
main = do
list <- wordList
print $ M.size list
对于文本文件,我正在使用转换为文本文件的pdf,因此无法提供它们,但是为了这个目的,几乎可以使用来自项目古腾堡的任何书籍。
编辑: 向脚本中添加了导入。
foldl'
而不是foldr
。在构建Map
之前,foldr
会构建与列表长度一样深的thunk。 - Daniel FischermapReduce
的第一个参数rseq
足以强制每个工作块真正并行执行吗?在parMap
中每个列表元素需要执行的工作量是否足够大,以确保并行任务的良好粒度?您尝试过在程序上运行threadscope以查看每个核心正在进行的操作吗?您尝试使用+RTS -s
运行程序,以查看垃圾收集花费了多少时间吗? - kosmikus