Lepsza alternatywa dla pmap w Clojure do równoległego łączenia umiarkowanie niedrogich funkcji z dużymi danymi?
Używając clojure, mam bardzo dużą ilość danych w sekwencji i chcę je przetwarzać równolegle, ze stosunkowo małą liczbą rdzeni (4 do 8).
Najłatwiej jest to zrobićpmap
zamiastmap
, aby odwzorować moją funkcję przetwarzania na sekwencję danych.Ale koszty koordynacji skutkują stratą netto w moim przypadku.
Myślę, że powodem jest topmap
zakłada, że funkcja odwzorowana na danych jest bardzo kosztowna. Patrząc na kod źródłowy pmap, wydaje się, że tworzyfuture
dla każdego elementu sekwencji kolejno, więc każde wywołanie funkcji występuje w osobnym wątku (cyklicznie nad liczbą dostępnych rdzeni).
Oto odpowiedni fragment źródła pmap:
(defn pmap
"Like map, except f is applied in parallel. Semi-lazy in that the
parallel computation stays ahead of the consumption, but doesn't
realize the entire result unless required. Only useful for
computationally intensive functions where the time of f dominates
the coordination overhead."
([f coll]
(let [n (+ 2 (.. Runtime getRuntime availableProcessors))
rets (map #(future (f %)) coll)
step (fn step [[x & xs :as vs] fs]
(lazy-seq
(if-let [s (seq fs)]
(cons (deref x) (step xs (rest s)))
(map deref vs))))]
(step rets (drop n rets))))
;; multi-collection form of pmap elided
W moim przypadku funkcja mapowana nie jest tak droga, ale sekwencja jest ogromna (miliony rekordów). Myślę, że koszt tworzenia i dereferencji, że wiele przyszłości jest tam, gdzie utracone jest równoległe wzmocnienie.
Czy moje rozumieniepmap
poprawny?
Czy jest lepszy wzór w clojure dla tego rodzaju niższego kosztu, ale masowo powtarzanego przetwarzania niżpmap
? Zastanawiam się nad fragmentowaniem sekwencji danych i uruchomieniem wątków na większych kawałkach.Czy to rozsądne podejście i jakie idiomy clojure będą działać?