2010-08-12 4 views
7

Disons que je définir la séquence de tous les nombres naturels de la manière suivante:Clojure Cartographie parallèle et des séquences infinies

(def naturals (iterate inc 0)) 

je définis également une fonction cartographie des Naturals à zéro qui prend un certain temps pour calculer comme ceci:

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

Notez le temps de calcul pour les evaulate s-expressions suivantes telle que mesurée par clojure.core/time.

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

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

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

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

(doall (take 30 naturals)) ; 0.385724 msecs

(range 30); 0,159374 msecs

pmap est ~ 6 fois plus rapide lorsqu'il est appelé avec une plage explicite qu'avec une section des naturels.

Puisque (= (range 30) (take 30 naturals)) renvoie true et que les deux objets sont de type clojure.lang.LazySeq, et que clojure évalue tous les arguments d'une fonction avant d'appeler la fonction, comment les détails de synchronisation ci-dessus peuvent-ils être expliqués?

Répondre

8

Je pense que cela est dû à ceci:

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 

Essayez ceci:

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

Notez qu'il saute 32 éléments à la fois. C'est ainsi que de nombreux éléments sont saisis par morceau pour une portée. Seqs pré-évalués pré-évaluer un tas d'éléments à l'avance pour augmenter les performances. Dans ce cas, il semble que pmap génère 32 threads dès que vous essayez d'attraper même un élément de la gamme.

Vous pouvez toujours placer vos éléments naturels dans un vecteur pour obtenir un comportement de segmentation.

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" 

(Notez que le temps est d'environ 4 x 500 ms, 4 étant le nombre de morceaux de 32 qu'il faut pour arriver à 100.)

D'autre part, vous ne voulez pas le comportement Chunking. 32 discussions à la fois, c'est beaucoup. Voir this question pour des exemples de comment un-chunkify un seq.

Questions connexes