7

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

但是,我希望有人可以解释改编自 O'Reilly 的 Programming Clojure 书中的一个简单示例的行为。

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

当我尝试取消引用时,通过这样做

(time @long-calculation)

它返回正确的结果(4999999950000000),但在我的机器上几乎是立即(0.045 毫秒)。

但是当我调用实际函数时,就像这样

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

我也得到了正确的结果,但所花费的时间要大得多(~ 5000 毫秒)。

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

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

4

1 回答 1

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"
于 2012-05-14T03:25:41.800 回答