Подтвердить что ты не робот

Сколько потоков выполняет Clojure функция pmap для операций URL-выборки?

Документация по функции pmap оставляет мне интересно, насколько она эффективна для чего-то вроде сбора коллекции XML-каналов через Интернет. Я не знаю, сколько одновременных операций выборки pmap будет появляться и что будет максимальным.

4b9b3361

Ответ 1

Если вы проверите источник, который вы видите:

> (use 'clojure.repl)
> (source 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."
  {:added "1.0"}
  ([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))))
  ([f coll & colls]
   (let [step (fn step [cs]
                (lazy-seq
                 (let [ss (map seq cs)]
                   (when (every? identity ss)
                     (cons (map first ss) (step (map rest ss)))))))]
     (pmap #(apply f %) (step (cons coll colls))))))

(+ 2 (.. Runtime getRuntime availableProcessors)) - это большой ключ. pmap будет захватывать первые (+ 2 processors) части работы и запускать их асинхронно через future. Поэтому, если у вас есть 2 ядра, он будет запускать 4 части работы за раз, стараясь немного опередить вас, но max должен быть 2 + n.

future в конечном итоге использует пул потоков ввода-вывода агента, который поддерживает неограниченное количество потоков. Он будет расти по мере того, как на него набрасывается работа и сжимается, если потоки не используются.

Ответ 2

Основываясь на замечательном ответе Алексея, объясняющем, как работает pmap, вот мое предложение для вашей ситуации:

(doall
  (map
    #(future (my-web-fetch-function %))
    list-of-xml-feeds-to-fetch))

Обоснование:

  • Вы хотите как можно больше работы в полете, так как большинство будет блокировать сетевое IO.
  • Будущее будет отключать асинхронную часть работы для каждого запроса, которая будет обрабатываться в пуле потоков. Вы можете позволить Clojure позаботиться об этом разумно.
  • Сопровождение на карте будет заставлять оценивать полную последовательность (то есть запуск всех запросов).
  • Ваш основной поток может начать разыгрывать фьючерсы сразу, и поэтому он может продолжать продвигаться по мере возврата отдельных результатов.

Ответ 3

Нет времени для написания длинного ответа, но есть http-агент clojure.contrib, который создает каждый запрос на получение/отправку в качестве своего собственного агента. Таким образом, вы можете запустить тысячу запросов, и все они будут выполняться параллельно и завершены по мере поступления результатов.

Ответ 4

Глядя на работу pmap, кажется, идет 32 потока за один раз, какое количество процессоров у вас есть, проблема в том, что карта будет идти впереди вычислений на 32, а фьючерсы начинаются сами по себе. (ОБРАЗЕЦ) (defn samplef [n] (println "starting " n) (Thread/sleep 10000) n) (def result (pmap samplef (range 0 100)))

; вы будете ждать 10 секунд и увидите 32 отпечатка, тогда когда вы возьмете 33-ю другую 32 ; печатает эти минуты, что вы одновременно выполняете 32 параллельных потока ; мне это не идеально ; САЛУДОС Фелипе