2012-05-14 211 views
7

我想了解Clojure期货,并且我已经看到了常见Clojure书籍的例子,并且有些例子中期货被用于并行计算(这似乎是有道理的)。了解Clojure期货

但是,我希望有人能够解释O'Reilly编程Clojure书中一个简单例子的行为。

(def long-calculation (future (apply + (range 1e8)))) 

当我尝试取消引用此,通过做

(time @long-calculation) 

它返回正确的结果(49999999.5亿),但几乎瞬间(0.045毫秒)我的机器上。

但是当我打电话的实际功能,像这样

(time (apply + (range 1e8))) 

我得到正确的结果为好,但花费的时间要大得多(〜5000毫秒)。

当我对未来进行解引用时,我的理解是创建一个新的线程来评估表达式 - 在这种情况下,我预计它也需要大约5000毫秒。

为什么取消引用的未来如此快速地返回正确的结果?

回答

11

未来的计算会在创建未来时开始(在单独的线程中)。

  • 如果未来还没有完成,块直到它完成,然后返回值(这可能:在你的情况下,计算只要你执行(def long-calculation ....)

    提领将做两件事情之一开始采取任意的时间,甚至从未完成,如果未来未能终止)

  • 如果未来已完成,则返回结果。这几乎是瞬时的(这就是为什么你看到非常快提领收益)

可以通过对比看到效果如下:

;; dereference before future completes 
(let [f (future (Thread/sleep 1000))] 
    (time @f)) 
=> "Elapsed time: 999.46176 msecs" 

;; dereference after future completes 
(let [f (future (Thread/sleep 1000))] 
    (Thread/sleep 2000) 
    (time @f)) 
=> "Elapsed time: 0.039598 msecs" 
+0

有没有使用大量的期货的缺点?我一直在编写一些在很多地方进行数值计算的代码。我可以不用原生的Java数组或类型提示,而只是编写惯用的函数代码和“将来”这些计算的结果呢? – endbegin

+2

期货相当轻量级,但确实有一些开销,所以我会避免使用它们进行极小的计算。如果你想同时进行计算,可以考虑使用'pmap' - 这是'map'的并发版本,它使用期货下的期货。话虽如此,如果您的代码真的是数字密集型的,那么如果您希望尽可能地利用CPU时间,那么最好使用Java数组*和* pmap/futures。 – mikera

+0

我尝试过使用pmap,但是只有当数据大小“很大”时(当然有多大才是主观的),它才会有用。我一直在通过实现一些简单的数字信号处理函数来学习Clojure,并且在单处理器/线程模式下使用本地Java数组的功能风格与seq抽象相比具有明显的速度优势。如果我使用期货,加速是如此巨大,以至于我使用本地代码还是功能代码都无关紧要。感觉像我失去了一些明显的东西。 – endbegin