Clojure 如何执行超时重试的函数?

Clojure 如何执行超时重试的函数?,clojure,timeout,future,Clojure,Timeout,Future,假设我使用以下代码来确保代码超时: (defmacro with-timeout [millis & body] `(let [future# (future ~@body)] (try (.get future# ~millis java.util.concurrent.TimeUnit/MILLISECONDS) (catch java.util.concurrent.TimeoutException x# (

假设我使用以下代码来确保代码超时:

(defmacro with-timeout [millis & body]
    `(let [future# (future ~@body)]
      (try
        (.get future# ~millis java.util.concurrent.TimeUnit/MILLISECONDS)
        (catch java.util.concurrent.TimeoutException x# 
          (do
            (future-cancel future#)
            nil)))))
现在,我想让它在5秒间隔后重试3次(如果超时)。我是在
TimeoutException
上写的,还是用其他方式写的


我的问题是:如何执行超时重试的函数?

这里有一个使用core.async的解决方案。它非常幼稚,因为它不处理错误处理。我也不确定它是否在超时时完全退出go调用

(ns async
  (:require [clojure.core.async :as a]))

(defmacro with-timeout [millis & body]
  `(loop [tries# 0]
     (if (> tries# 3)
       (throw (Exception. "Timed out. (3)"))
       (let [result# (a/alt!!
                       (a/go ~@body)      ([v# ch] v#)
                       (a/timeout ~millis) :async/timed-out)]
         (if (= result# :async/timed-out)
           (recur (inc tries#))
           result#)))))

deref
有一个接受超时的变量。使用它,我们可以在不使用Java互操作的情况下实现带超时的

(defmacro with-timeout [millis & body]
  `(loop [tries# 3]
     (if (pos? tries#)
       (let [future# (future ~@body)
             result# (deref future# ~millis ::timeout)]
         (if (= result# ::timeout)
           (do (future-cancel future#)
               (recur (dec tries#)))
           result#)))))
(这不是100%的“卫生”,因为
::timeout
sentinel值理论上可能与
正文
表单返回的值冲突。)