Я пытаюсь склонить голову вокруг параллельных стратегий. Я думаю, что понимаю, что делают каждый из комбинаторов, но каждый раз, когда я пытаюсь использовать их с более чем 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
Что касается текстовых файлов, я использую PDFs преобразуются в текстовые файлы, так что я не могу представить их, но для этой цели, практически любую книгу/книги из проекта Гутенберг должны делать.
Редактировать: Добавлен импорт в скрипт
'histogram = foldr (\ k -> M.insertWith '(+) k 1) M.empty. фильтр (не. isStopWord). T.words' должен скорее использовать 'foldl''. 'Foldr' строит thunk так глубоко, как список задолго до того, как он может начать строить' Map'. –
Было бы гораздо легче ответить на такой вопрос, если бы вы представили небольшой и полный пример. Не задумываясь подробно: Вы уверены, что 'rseq' как первый аргумент' mapReduce' достаточно, чтобы заставить каждый кусок работы действительно выполняться параллельно? Является ли объем работы над элементом списка в parMap достаточно большим, чтобы обеспечить хорошую детализацию параллельных задач? Вы пробовали работать с нитками в своей программе, чтобы узнать, что происходит на каждом ядре? Вы пробовали работать с '+ RTS -s', чтобы узнать, сколько времени потрачено на сбор мусора? – kosmikus
kosmikus, какой полный пример вы имеете в виду? Помимо импорта этот скрипт полностью запущен. Для rseq/rdeepseq я пробовал с другими комбинациями без везения. Что касается parMap, я также попробовал карту с parListChunk и parListN. А что касается потолочной камеры, то, как представляется, неуклонно действуют как действие, так и gc. -s сказал, что это было 60% рабочего времени, что было лучше, чем случай -N1. – Masse