2016-07-04 6 views
1

Ich habe etwas Haskell-Code, der viel von sich gegenseitig nicht überlappenden Dingen zu einer großen (65.5k Elemente) Liste von Elementen macht. Dies schien eine gute Lösung für die Parallelisierung zu sein, die ich unter Verwendung von Control.Parallel.Strategies.parBuffer übernommen habe. Das hat geholfen, aber ich bin überzeugt, dass die Arbeit zu feinkörnig ist, und ich würde auch gerne die Liste in Chunks bearbeiten (wie es bei Control.Parallel.Strategies.parListChunk der Fall wäre). Da meine Liste jedoch groß ist, haben Experimente mit nurparListChunk nicht so viel Beschleunigung, wie die gesamte 65-ungerade-tausend-Artikel-Liste ausgewertet werden musste, um diese Arbeit zu machen (wie der Speicherverbrauch des Programms zeigte) .Wie kombiniere ich die Vorteile von `` parBuffer`` und `` parListChunk``?

Gibt es eine Möglichkeit, eine Strategy zu schreiben, die mir die Vorteile der gibt sowohlparBuffer (dh die Liste wird als faul Puffer mit einer steuerbaren Menge der Auswertung behandelt) und auch parListChunk (dh die Arbeit gliedert sich in Stücke, die aus mehreren Elementen der Liste anstelle von Individuen bestehen). Ich bin mir nicht sicher, wie ich das machen soll.

Edit: Wie pro Antrag, hier ist das, was mit ich arbeite, komplett mit Erläuterungen:

parBufferMap :: Int -> Strategy b -> (a -> b) -> [a] -> [b] 
parBufferMap i strat f = withStrategy (parBuffer i strat) . fmap f 

main :: IO() 
main = do 
    let allTables = genAllTables 4 -- a list of 65.5k Tables    
    let results = parBufferMap 512 rdeepseq theNeedful allTables -- theNeedful is what I need to do to each Table, independently of each other 
    let indexed = zip [1..] results 
    let stringified = stringify <$> indexed -- make them pretty for output 
    void . traverse putStrLn $ stringified -- actually print them 

Mein Ziel ist es, die results Berechnung zu ersetzen, wie es (mit nurparBufferMap) mit etwas das vereint die Vorteile von parBufferMap und parListChunk.

+0

Was meinst du genau damit, "viele einander nicht überlappende Dinge zu tun"? Irgendein Code und/oder Pseudocode würde helfen. – ErikR

+0

@ErikR Code hinzugefügt, um (hoffentlich) zu zeigen, wonach ich suche. –

Antwort

1

So scheint es, Sie wan zu berechnen:

map theNeedful allTables 

aber Sie wollen die Zuordnung in Chargen von 512 Tabellen zu tun.

Sieht das so aus, als ob es für Sie funktioniert?

-- assuming: 
theNeedful :: Table -> Result 

nthreads = 4 -- number of threads to keep busy 
allTables = ... 
allBatches = chunksOf 512 allTables -- from Data.List.Split 

doBatch :: [Table] -> [Result] 
doBatch tables = map theNeedful tables 

results :: [Result] 
results = concat $ withStrategy (parBuffer nthreads rdeepseq) (map doBatch allBatches) 
... 

In Worten:

  1. Break up die Tabellen in Stücke von 512 Tabellen jeweils
  2. Karte doBatch über alle Chargen
  3. ausführen parBuffer auf dieser Liste von Berechnungen
  4. concat die resultierende Liste
+0

Dies ist im Grunde, was ich getan habe - ich frage mich, ob diese Art von Sache notwendig ist, anstatt nur "Strategien" zu kombinieren, denke ich. –