Использование clojure У меня очень большой объем данных в последовательности, и я хочу обрабатывать их параллельно, с относительно небольшим количеством ядер (от 4 до 8).
Самое простое, что нужно сделать, это использовать pmap
вместо map
, чтобы отобразить мою функцию обработки в последовательности данных. Но координационные издержки приводят к чистым потерям в моем случае .
Я думаю, причина в том, что pmap
предполагает, что функция, сопоставленная с данными, очень дорогая . Глядя на исходный код pmap, он, по-видимому, строит future
для каждого элемента последовательности по очереди, поэтому каждый вызов функции происходит в отдельном потоке (циклически изменяя количество доступных ядер).
Вот соответствующий фрагмент исходного кода 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
В моем случае отображенная функция не так уж дорога, но последовательность огромна (миллионы записей). Я думаю, что стоимость создания и разыменования такого большого количества фьючерсов - это то, где параллельная прибыль теряется в накладных расходах.
Правильно ли мое понимание pmap
?
Есть ли лучший шаблон в укупорке для такого рода более дешевой, но массово повторяющейся обработки, чем pmap
? Я подумываю о том, чтобы как-то разбить последовательность данных, а затем запустить потоки на больших кусках. Это разумный подход и какие идиомы clojure будут работать?