10

有没有办法在未来设置手表,以便在完成时触发回调?

像这样的东西?

> (def a (future (Thread/sleep 1000) "Hello World!")
> (when-done a (println @a))

...waits for 1sec...
;; =>  "Hello World"
4

5 回答 5

16

您可以启动另一个监视未来的任务,然后运行该函数。在这种情况下,我将使用另一个未来。它很好地包含在一个完成时的功能中:

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
于 2013-05-02T23:53:58.263 回答
5

对于非常简单的情况:如果您不想阻塞并且不关心结果,只需在将来的定义中添加回调。

(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://github.com/ztellman/manifold

https://github.com/clojure/core.async

于 2015-10-30T00:38:12.293 回答
2

已接受答案的扩展

请注意以下警告:

使用上述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))

于 2020-12-14T00:38:59.683 回答
0

我没有增加额外的时间Thread/Sleep,而是利用这样一个事实,即@future-ref对未来的任何引用都将等到未来完成。

(defn  wait-for
  [futures-to-complete]
  (every? #(@%) futures-to-complete))
于 2019-06-08T18:01:45.437 回答