Ich versuche, mich um parallele Strategien zu kümmern. Ich denke, ich verstehe, was jeder der Kombinierer macht, aber jedes Mal, wenn ich versuche, sie mit mehr als einem Kern zu verwenden, verlangsamt sich das Programm beträchtlich.Effiziente parallele Strategien
Zum Beispiel eine Weile zurück Ich habe versucht, Histogramme (und davon eindeutige Wörter) aus ~ 700 Dokumente zu berechnen. Ich dachte, dass die Granularität auf Dateiebene in Ordnung wäre. Mit -N4
bekomme ich 1,70 Work Balance. Mit -N1
läuft es jedoch in der Hälfte der Zeit als mit -N4
. Ich bin nicht sicher, was die Frage wirklich ist, aber ich würde gerne wissen, wie man entscheidet, wo/wann/wie man parallelisiert und etwas Verständnis dafür bekommt. Wie würde dies parallelisiert werden, so dass die Geschwindigkeit mit Kernen zunimmt anstatt zu sinken?
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
Wie für die Textdateien, ich bin mit pdfs umgewandelt in Text-Dateien, damit ich sie nicht bieten kann, aber für den Zweck, fast jedes Buch/Bücher von Projekt Gutenberg tun sollen.
bearbeiten: hinzugefügt Importe Skript
'Histogramm = foldr (\ k -> M.insertWith '(+) k 1) M.leer. filter (nicht. isStopWord). T.words' sollte eher eine 'foldl' verwenden. Der 'foldr' erstellt ein Thunk so tief wie die Liste ist lange bevor es beginnen kann, die' Map' zu erstellen. –
Es wäre viel einfacher, eine solche Frage zu beantworten, wenn Sie ein kleines und vollständiges Beispiel liefern würden. Ohne genau ins Detail zu schauen: Sind Sie sicher, dass 'rseq' als erster arg von' mapReduce' genug ist, um zu erzwingen, dass jeder Teil der Arbeit wirklich parallel gemacht wird? Ist der Arbeitsaufwand pro Listenelement in 'parMap' groß genug, um eine gute Granularität der parallelen Aufgaben zu gewährleisten? Haben Sie versucht, threadscope in Ihrem Programm auszuführen, um zu sehen, was auf jedem Kern vor sich geht? Haben Sie versucht, mit '+ RTS -s' zu laufen, um zu sehen, wie viel Zeit in der Garbage Collection verbracht wird? – kosmikus
kosmikus, was für ein komplettes Beispiel meinst du? Abgesehen von Importen ist das Skript vollständig lauffähig. Für rseq/rdeepseq, versuchte ich mit anderen Kombinationen ohne Glück. Wie für ParMap, habe ich auch versucht, mit ParListChunk und ParListN Karte. Und was den threadscope anbelangt, schien es sowohl Action als auch GC zu geben. -s sagte, dass es 60% Arbeitszeit war, was besser war als der Fall -N1. – Masse