Ich versuche, eine Datei mit einer Million Zeilen zu analysieren, jede Zeile ist eine JSON-Zeichenfolge mit einigen Informationen über ein Buch (Autor, Inhalt usw.). Ich verwende iota, um die Datei zu laden, da mein Programm OutOfMemoryError
wirft, wenn ich versuche, slurp
zu verwenden. Ich verwende auch cheshire, um die Zeichenfolgen zu analysieren. Das Programm lädt einfach eine Datei und zählt alle Wörter in allen Büchern.Warum verwendet pmap | reducers/map nicht alle CPU-Kerne?
Mein erster Versuch enthalten pmap
, um die schwere Arbeit zu tun, ich dachte, das würde im Wesentlichen alle meine CPU-Kerne nutzen.
(ns multicore-parsing.core
(:require [cheshire.core :as json]
[iota :as io]
[clojure.string :as string]
[clojure.core.reducers :as r]))
(defn words-pmap
[filename]
(letfn [(parse-with-keywords [str]
(json/parse-string str true))
(words [book]
(string/split (:contents book) #"\s+"))]
(->>
(io/vec filename)
(pmap parse-with-keywords)
(pmap words)
(r/reduce #(apply conj %1 %2) #{})
(count))))
Während es alle Kerne zu verwenden scheint, jeder Kern nur selten verwendet mehr als 50% seiner Kapazität, meine Vermutung ist, dass es mit Losgröße pmap zu tun hat, und so stolperte ich über relatively old question wo einige Kommentare Verweise auf die clojure.core.reducers
Bibliothek.
habe ich beschlossen, die Funktion mit reducers/map
neu zu schreiben:
(defn words-reducers
[filename]
(letfn [(parse-with-keywords [str]
(json/parse-string str true))
(words [book]
(string/split (:contents book) #"\s+"))]
(->>
(io/vec filename)
(r/map parse-with-keywords)
(r/map words)
(r/reduce #(apply conj %1 %2) #{})
(count))))
Aber die CPU-Auslastung ist schlimmer, und es dauert noch länger im Vergleich zu der vorherigen Ausführung zu beenden:
multicore-parsing.core=> (time (words-pmap "./dummy_data.txt"))
"Elapsed time: 20899.088919 msecs"
546
multicore-parsing.core=> (time (words-reducers "./dummy_data.txt"))
"Elapsed time: 28790.976455 msecs"
546
Was bin ich falsch machen? Ist mmap loading + die richtige Vorgehensweise beim Parsen einer großen Datei?
EDIT: this ist die Datei, die ich benutze.
EDIT2: Hier sind die Timings mit iota/seq
statt iota/vec
:
multicore-parsing.core=> (time (words-reducers "./dummy_data.txt"))
"Elapsed time: 160981.224565 msecs"
546
multicore-parsing.core=> (time (words-pmap "./dummy_data.txt"))
"Elapsed time: 160296.482722 msecs"
546
Es sieht aus wie 'io/vec' die gesamte Datei durchsucht einen Index von wo die Linien zu bauen. Erhalten Sie andere Ergebnisse, wenn Sie 'io/seq' versuchen? –
@NathanDavis Ich habe es gerade versucht, die Zeiten sind schlechter. Lass mich die Frage aktualisieren – eugecm
[Dieses Gespräch] (https://www.youtube.com/watch?v = BzKjIk0vgzE) von Leon Barrett, Autor von [Claypoole] (https://github.com/TheClimateCorporation/claypoole), könnte einige relevante Informationen haben. Es erklärt 'pmap' im Detail, einschließlich, warum es oft die CPU nicht sättigt, und ein wenig darüber, warum das Einspeisen eines' pmap' in ein anderes überraschende Ergebnisse haben kann. Wenn Sie hauptsächlich nach einer Möglichkeit suchen, Ihre CPU zu sättigen, könnte Claypoole genau das sein, was Sie brauchen. –