concurrency clojure pmap

concurrency - ¿Cuántos subprocesos genera la función pmap de Clojure para las operaciones de recuperación de URL?



(4)

No hay tiempo para escribir una respuesta larga, pero hay un clojure.contrib http-agent que crea cada solicitud de obtención / publicación como su propio agente. Así que puedes disparar mil solicitudes y todas se ejecutarán en paralelo y se completarán a medida que aparezcan los resultados.

La documentación sobre la función pmap me hace preguntarme qué tan eficiente sería para algo como obtener una colección de fuentes XML a través de la web. No tengo idea de cuántas operaciones de recuperación simultáneas pmap generaría y cuál sería el máximo.


Si marca la fuente que ve:

> (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))))))

El (+ 2 (.. Runtime getRuntime availableProcessors)) es una gran pista allí. pmap tomará los primeros (+ 2 processors) de trabajo y los ejecutará de forma asíncrona a través del future . Entonces, si tiene 2 núcleos, se lanzarán 4 piezas de trabajo a la vez, tratando de mantenerse un poco por delante, pero el máximo debería ser 2 + n.

future finalmente usa el grupo de subprocesos de E / S del agente que admite un número ilimitado de subprocesos. Crecerá a medida que se le arroje trabajo y se reducirá si los hilos no se utilizan.


Si observamos el funcionamiento de pmap, parece que se van 32 subprocesos a la vez, independientemente de la cantidad de procesadores que tenga, el problema es que el mapa se adelantará al cálculo en 32 y los futuros se iniciarán por sí solos. (MUESTRA) (defn samplef [n] (println "starting " n) (Thread/sleep 10000) n) (def result (pmap samplef (range 0 100)))

; esperará 10 segundos y verá 32 impresiones luego, cuando tome la 33 y otras 32; imprime estos minutos que está haciendo 32 subprocesos simultáneos a la vez; para mí esto no es perfecto; SALUDOS Felipe


Sobre la base de la excelente respuesta de Alex, que explica cómo funciona PMAP, esta es mi sugerencia para su situación:

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

Razón fundamental:

  • Desea tantos trabajos en vuelo como pueda, ya que la mayoría bloqueará en la red IO.
  • El futuro iniciará un trabajo asíncrono para cada solicitud, que se manejará en un grupo de subprocesos. Puedes dejar que Clojure se encargue de eso de manera inteligente.
  • El doall en el mapa forzará la evaluación de la secuencia completa (es decir, el lanzamiento de todas las solicitudes).
  • Su hilo principal puede comenzar a desreferenciar los futuros de inmediato y, por lo tanto, puede continuar progresando a medida que los resultados individuales regresan.