执行超时功能

Ham*_*aya 17 clojure

在一个时间限制内执行函数的惯用方法是什么?就像是,

(with-timeout 5000
 (do-somthing))
Run Code Online (Sandbox Code Playgroud)

除非do-something返回5000以内抛出异常或返回nil.

编辑:在有人指出它之前,

clojure(with-timeout ... macro)

但随着这一点,未来继续执行,在我的情况下不起作用.

mik*_*era 17

我认为你可以通过在期货中使用超时功能来合理可靠地做到这一点:

  (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)))))
Run Code Online (Sandbox Code Playgroud)

一些实验验证你需要做一个future-cancel来阻止未来的线程继续执行....


ama*_*loy 13

这不是你可以在JVM上100%可靠地完成的事情.一段时间后停止某事的唯一方法是给它一个新线程,然后在你希望它停止时发送该线程异常.但是他们的代码可以捕获异常,或者他们可以启动另一个你无法控制的线程,或者......

但大部分时间,特别是如果你控制正在超时的代码,你可以像在clojail中那样做:

如果你想做得更漂亮,你可以定义一个宏

(defmacro with-timeout [time & body]
  `(thunk-timeout (fn [] ~@body) ~time))
Run Code Online (Sandbox Code Playgroud)

  • 上面的链接已经死了.也许更新的更新:https://github.com/flatland/clojail/blob/master/src/clojail/core.clj#L26 (2认同)

Jer*_*ijk 10

关于什么?

    (defn timeout [timeout-ms callback]
     (let [fut (future (callback))
           ret (deref fut timeout-ms ::timed-out)]
       (when (= ret ::timed-out)
         (future-cancel fut))
       ret))

    (timeout 100 #(Thread/sleep 1000))

    ;=> :user/timed-out
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案 - 没有依赖项,没有宏:) (2认同)

小智 6

使用 Clojure 的通道设施轻而易举 https://github.com/clojure/core.async

需要各自的命名空间

(:require [clojure.core.async :refer [>! alts!! timeout chan go]])
Run Code Online (Sandbox Code Playgroud)

函数 wait 需要超时 [ms]、函数 [f] 和可选参数 [args]

(defn wait [ms f & args]
  (let [c (chan)]
    (go (>! c (apply f args)))
    (first (alts!! [c (timeout ms)]))))
Run Code Online (Sandbox Code Playgroud)

第三行将对 f 的调用弹出到另一个线程。第四行消耗函数调用的结果或(如果更快)超时。

考虑以下示例调用

(wait 1000 (fn [] (do (Thread/sleep 100) 2)))
=> 2
Run Code Online (Sandbox Code Playgroud)

(wait 50 (fn [] (do (Thread/sleep 100) 2)))
=> nil
Run Code Online (Sandbox Code Playgroud)