Clojure "wiederholt" lässt "Zukunft" nacheinander laufen

12

Während dieses Schnipsels

(dorun 
  (map deref 
    (map #(future 
            (println % (Thread/currentThread))) 
         (range 10))))

druckt 10 gemischte Linien mit verschiedenen Fäden:

0 #object[java.lang.Thread 0x5f1b4a83 Thread[clojure-agent-send-off-pool-26,5,main]]                                                                                                                           
2 #object[java.lang.Thread 1 0x79dfba1f #object[Thread[clojure-agent-send-off-pool-28,5,main]java.lang.Thread]                                                                                                 
3 4 #object[java.lang.Thread #object[java.lang.Thread 0x7ef7224f Thread[clojure-agent-send-off-pool-27,5,main]0x5f1b4a83 ]Thread[clojure-agent-send-off-pool-26,5,main]]                                       
5                                                                                                                                                                                                              
67  #object[java.lang.Thread #object[0x79dfba1f java.lang.Thread Thread[clojure-agent-send-off-pool-28,5,main]]0x77526645                                                                                      
 8 #object[java.lang.Thread #object[java.lang.ThreadThread[clojure-agent-send-off-pool-29,5,main] ]9 #object[java.lang.Thread 0xc143aa5 0x7ef7224f                                                             Thread[clojure-agent-send-off-pool-31,5,main]]Thread[clojure-agent-send-off-pool-27,5,main]]                                                                                                                       

0x1ce8675f 0x379ae862 Thread[clojure-agent-send-off-pool-30,5,main]Thread[clojure-agent-send-off-pool-32,5,main]]]

wie ich erwarten würde, der folgende Ausschnitt:

(dorun
  (map deref 
    (map #(future 
            (println % (Thread/currentThread))) 
         (repeatedly 10 #(identity 42)))))

erzeugt 10 sauber ausgerichtete Strings mit demselben Thread:

42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                                                                                                                              
42 #object[java.lang.Thread 0x1e1b7ffb Thread[clojure-agent-send-off-pool-39,5,main]]                          

Dies zeigt deutlich, dass die Futures nicht parallel, sondern jeweils im selben Thread ausgeführt werden.

Dies geschieht nur mit repeatedly, selbst wenn ich die Sequenz doallzuerst realisiere, aber Vektoren, ranges oder andere Sequenzen führen alle zu einer parallelen Ausführung.

Warum wird zukünftig an denselben Thread gesendet, wenn er repeatedlyverwendet wird?

Vielen Dank!

Rick77
quelle

Antworten:

13

Das funktioniert:

(dorun (map deref (doall (map #(future (println % (Thread/currentThread))) (repeatedly 10 #(identity 42))))))

Das Problem besteht darin , dass rangeein produziert Chunked Sequenz während repeatedlyeiner produziert unchunked Sequenz. Die Karte ist faul. repeatedlyWenn Sie also eine Zukunft erstellen, dann derefen, dann die nächste Zukunft erstellen und dann dereffizieren. In dem rangeFall, dass die Sequenz aufgeteilt ist, erstellen Sie alle Futures und dann derefalle.

Hier ist eine weitere unterhaltsame Möglichkeit, den Unterschied zwischen dem Verhalten von Chunked- und Unchunked-Sequenzen zu beobachten.

=> (first (map prn (range 10)))
0
1
2
3
4
5
6
7
8
9
nil
=> (first (map prn (repeatedly 10 #(identity 13))))
13
nil

Die Größe der Chunks beträgt normalerweise 32 (aber ich denke, das ist nirgendwo garantiert), wie man sehen kann, wenn man rennt (first (map prn (range 1000))).

Chunking ist eine dieser versteckten Funktionen von Clojure, die Sie normalerweise lernen, wenn es Sie zum ersten Mal beißt :)

opqdonut
quelle
1
whoa! [Conspiracy Keanu Reaves memehere einfügen]: Ich habe das nicht kommen sehen! Vielen Dank für die tolle Antwort!
Rick77
1
Kein Problem! Ich habe diese Frage nur gesehen, weil Sie sie auf #clojure auf freenode gepostet haben.
Opqdonut