Clojure "berulang kali" membuat "masa depan" berjalan berurutan

12

Sementara potongan ini

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

mencetak 10 garis intermixed yang menampilkan utas berbeda:

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]]]

seperti yang saya harapkan, cuplikan berikut:

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

menghasilkan 10 string yang selaras rapi dengan utas yang sama:

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]]                          

yang jelas menunjukkan bahwa futures tidak berjalan secara paralel, tetapi masing-masing di utas yang sama.

Ini terjadi hanya dengan repeatedly, bahkan jika saya menyadari urutan dengan doallpertama, tetapi vektor, ranges atau urutan lainnya semua menghasilkan eksekusi paralel.

Mengapa pengiriman nanti ke utas yang sama saat repeatedlydigunakan?

Terima kasih!

Rick77
sumber

Jawaban:

13

Ini bekerja:

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

Masalahnya adalah bahwa rangemenghasilkan urutan chunked sementara repeatedlymenghasilkan urutan unchunked . Peta itu malas, jadi repeatedlyjika Anda menciptakan masa depan, lalu menghapusnya, lalu menciptakan masa depan berikutnya, lalu menghapusnya. Dalam rangehal urutannya terpotong sehingga Anda menciptakan semua masa depan dan kemudian derefsemuanya.

Berikut ini cara lain yang menyenangkan untuk mengamati perbedaan antara perilaku urutan chunked dan unchunked.

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

Ukuran bongkahan biasanya 32 (tapi saya pikir itu tidak dijamin di mana saja), seperti yang bisa dilihat jika Anda berlari (first (map prn (range 1000))).

Chunking adalah salah satu fitur tersembunyi Clojure yang biasanya Anda pelajari ketika pertama kali menggigit Anda :)

opqdonut
sumber
1
tunggu! [masukkan Konspirasi Keanu Reaves memehere]: Saya tidak melihat ini datang! Terima kasih atas jawaban yang bagus!
Rick77
1
Tidak masalah! Saya hanya melihat pertanyaan ini karena Anda mempostingnya di #clojure di freenode.
opqdonut