Отображение параллели Clojure и бесконечные последовательности

Скажем, я определяю последовательность всех натуральных чисел следующим образом:

(def naturals (iterate inc 0))

Я также определяю функцию, отображающую naturals на ноль, который требует времени для вычислений как так:

(defn hard-comp [_] (Thread/sleep 500))

Отметьте время вычисления для оценивания следующих s-выражений, как измеряется clojure.core/time.

(dorun (map hard-comp (range 30))) ; 15 010,367496 национальной безопасности

(dorun (pmap hard-comp (range 30))) ; 537,044554 национальной безопасности

(dorun (map hard-comp (doall (take 30 naturals))))) ; 15 009,488499 национальной безопасности

(dorun (pmap hard-comp (doall (take 30 naturals)))) ; 3 004,499013 национальной безопасности

(doall (take 30 naturals)) ; 0,385724 национальной безопасности

(range 30) ; 0,159374 национальной безопасности

pmap в ~6 раз быстрее при вызове с явным диапазоном, чем с разделом naturals.

С тех пор (= (range 30) (take 30 naturals)) возвращает true, и оба объекта имеют тип clojure.lang.LazySeq, и clojure оценивает все аргументы функции прежде, чем вызвать функцию, как может вышеупомянутые детали синхронизации быть объясненным?

7
задан Robert McIntyre 12 August 2010 в 03:39
поделиться

1 ответ

Я предполагаю, что это происходит из-за этого:

user> (chunked-seq? (seq (range 30)))
true
user> (chunked-seq? (seq (take 30 naturals)))
false
user> (class (next (range 30)))
clojure.lang.ChunkedCons
user> (class (next (take 30 naturals)))
clojure.lang.Cons

Попробуйте следующее:

user> (defn hard-comp [x] (println x) (Thread/sleep 500))
#'user/hard-comp
user> (time (dorun (pmap hard-comp (range 100))))

Обратите внимание, что он перескакивает по 32 элементам за раз. Вот сколько элементов захватывается за кусок для диапазона. Разделенные на фрагменты последовательности заранее оценивают кучу элементов для повышения производительности. В этом случае похоже, что pmap фрагментарно порождает 32 потока, как только вы пытаетесь захватить хотя бы один элемент из диапазона.

Вы всегда можете поместить естественные элементы в вектор, чтобы получить поведение фрагментов.

user> (time (dorun (pmap hard-comp (range 100))))
"Elapsed time: 2004.680192 msecs"
user> (time (dorun (pmap hard-comp (vec (take 100 naturals)))))
"Elapsed time: 2005.887754 msecs"

(Обратите внимание, что время составляет примерно 4 x 500 мс, где 4 - это количество фрагментов из 32, которое требуется для достижения 100).

С другой стороны, вам может не потребоваться поведение фрагментов. 32 потока одновременно - это много. См. этот вопрос , где приведены примеры того, как разделить последовательность на части.

8
ответ дан 7 December 2019 в 05:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: