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.