2010-08-12 10 views
7

Digamos que definir la secuencia de todos los números naturales de la siguiente manera:Clojure Mapeo paralelo y secuencias infinitas

(def naturals (iterate inc 0)) 

también defino una función de mapeo de los naturales a cero que toma un tiempo para calcular de este modo:

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

Nota el tiempo de cálculo para evaulate los siguientes s-expresiones medida por clojure.core/time.

(dorun (map hard-comp (range 30))) ; 15010,367496 mseg

(dorun (pmap hard-comp (range 30))) ; 537.044554 mseg

(dorun (map hard-comp (doall (take 30 naturals))))) ; 15009.488499 mseg

(dorun (pmap hard-comp (doall (take 30 naturals)))) ;3004.499013 mseg

(doall (take 30 naturals)) ; 0.385724 mseg

(range 30); 0.159374 msecs

pmap es ~ 6 veces más rápido cuando se lo llama con un rango explícito que con una sección de los naturales.

Dado que (= (range 30) (take 30 naturals)) devuelve verdadero y ambos objetos son del tipo clojure.lang.LazySeq, y clojure evacua todos los argumentos a una función antes de llamar a la función, ¿cómo se pueden explicar los detalles de temporización anteriores?

Respuesta

8

Mi conjetura es que es debido a esto:

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 

Prueba esto:

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

Nota que salte 32 elementos a la vez. Así es como muchos elementos son agarrados por porción para un rango. Seqs fragmentados evalúan previamente varios elementos antes de tiempo para aumentar el rendimiento. En este caso, parece que pmap genera groseramente 32 subprocesos tan pronto como intentas obtener incluso un elemento del rango.

Siempre puedes incluir tus elementos naturales en un vector para obtener un comportamiento de fragmentación.

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" 

(Tenga en cuenta que el tiempo es de aproximadamente 4 x 500 ms, siendo 4 el número de trozos de 32 que tarda en llegar a 100.)

Por otro lado, puede que no desee el comportamiento de fragmentación. 32 hilos a la vez es mucho. Consulte this question para ver ejemplos de cómo desvincular una secuencia.

Cuestiones relacionadas