有没有办法在未来设置手表,以便在完成时触发回调?
像这样的东西?
> (def a (future (Thread/sleep 1000) "Hello World!")
> (when-done a (println @a))
...waits for 1sec...
;; => "Hello World"
有没有办法在未来设置手表,以便在完成时触发回调?
像这样的东西?
> (def a (future (Thread/sleep 1000) "Hello World!")
> (when-done a (println @a))
...waits for 1sec...
;; => "Hello World"
您可以启动另一个监视未来的任务,然后运行该函数。在这种情况下,我将使用另一个未来。它很好地包含在一个完成时的功能中:
user=> (defn when-done [future-to-watch function-to-call]
(future (function-to-call @future-to-watch)))
user=> (def meaning-of-the-universe
(let [f (future (Thread/sleep 10000) 42)]
(when-done f #(println "future available and the answer is:" %))
f))
#'user/meaning-of-the-universe
... waiting ...
user=> future available and the answer is: 42
user=> @meaning-of-the-universe
42
对于非常简单的情况:如果您不想阻塞并且不关心结果,只需在将来的定义中添加回调。
(future (a-taking-time-computation) (the-callback))
如果您关心结果,请在回调中使用 comp
(future (the-callback (a-taking-time-computation)))
或者
(future (-> input a-taking-time-computation callback))
从语义上讲,Java 等效代码是:
final MyCallBack callbackObj = new MyCallBack();
new Thread() {
public void run() {
a-taking-time-computation();
callbackObj.call();
}
}.start()
对于复杂的情况,您可能需要查看:
我在谷歌上发现了这个看起来很有趣的帖子:
https://groups.google.com/forum/?fromgroups=#!topic/clojure-dev/7BKQi9nWwAw
http://dev.clojure.org/display/design/Promises
https://github.com/stuartsierra/cljque/blob/master/src/cljque/promises.clj
已接受答案的扩展
请注意以下警告:
使用上述when-done
实现,如果未来被取消,回调将不会被调用。那是
(do
(def f0 (future (Thread/sleep 1000)))
(when-done f0 (fn [e] (println "THEN=>" e)))
(Thread/sleep 500)
(future-cancel f0))
不会打印,因为取消的未来的 deref 调用会引发异常。
如果您需要回调发生,我建议:
(defn then
"Run a future waiting on another, and invoke
the callback with the exit value if the future completes,
or invoke the callback with no args if the future is cancelled"
[fut cb]
(future
(try
(cb @fut)
(catch java.util.concurrent.CancellationException e
(cb)))))
所以现在这将打印:
(do
(def f0 (future (Thread/sleep 1000)))
(then f0 (fn
([] (println "CANCELLED"))
([e] (println "THEN=>" e))))
(Thread/sleep 500)
(future-cancel f0))
我没有增加额外的时间Thread/Sleep
,而是利用这样一个事实,即@future-ref
对未来的任何引用都将等到未来完成。
(defn wait-for
[futures-to-complete]
(every? #(@%) futures-to-complete))