【问题标题】:Clojure "repeatedly" makes "future" run sequentiallyClojure“反复”让“未来”按顺序运行
【发布时间】:2020-03-06 10:08:35
【问题描述】:

虽然这个sn-p

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

打印 10 条显示不同线程的混合行:

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

如我所料,以下 sn-p:

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

用同一线程产生 10 个整齐排列的字符串:

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

这清楚地表明期货不是并行运行的,而是每个都在同一个线程中。

这种情况只发生在repeatedly 上,即使我首先实现了doall 的序列,但是向量、ranges 或其他序列都会导致并行执行。

当使用repeatedly 时,为什么将来会分派到同一个线程?

谢谢!

【问题讨论】:

    标签: clojure


    【解决方案1】:

    这行得通:

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

    问题是range 产生了一个chunked 序列,而repeatedly 产生了一个unchunked 序列。 Map 是懒惰的,所以在repeatedly 的情况下,您正在创建一个future,然后解除它,然后创建下一个future,然后解除它。在 range 的情况下,序列是分块的,因此您要创建所有期货,然后 derefing 所有期货。

    这是观察分块和非分块序列行为差异的另一种有趣方式。

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

    块的大小通常是 32(但我认为这在任何地方都不能保证),如果你运行 (first (map prn (range 1000))) 可以看到。

    分块是 Clojure 的隐藏功能之一,您通常会在它第一次咬你时了解它:)

    【讨论】:

    • 哇! [插入阴谋 Keanu Reaves memehere]:我没想到会这样!感谢您的精彩回答!
    • 没问题!我之所以看到这个问题,是因为您将其发布在 freenode 上的#clojure 上。
    猜你喜欢
    • 2019-10-19
    • 1970-01-01
    • 2016-07-25
    • 2022-01-04
    • 1970-01-01
    • 2015-02-15
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多