clojure (with-timeout … macro)

前端 未结 3 719
-上瘾入骨i
-上瘾入骨i 2021-02-09 01:50

I\'m looking for a macro that will throw an exception if an expression takes longer than X seconds to complete.

3条回答
  •  南方客
    南方客 (楼主)
    2021-02-09 02:48

    I came across this thread recently while asking the same question. I wasn't completely satisfied with the answers given so I cobbled together an alternative solution. This solution will run your code in the current thread and spin of a future to interrupt it after a set timeout in ms.

    (defn invoke-timeout [f timeout-ms]
      (let [thr (Thread/currentThread)
            fut (future (Thread/sleep timeout-ms)
                        (.interrupt thr))]
        (try (f)
             (catch InterruptedException e
               (throw (TimeoutException. "Execution timed out!")))
             (finally
               (future-cancel fut)))))
    
    (defmacro timeout [ms & body] `(invoke-timeout (fn [] ~@body) ~ms))
    

    You would use it in your code like this:

    (timeout 1000 your-code)
    

    OR

    (invoke-timeout #(your-code) 1000)
    

    One caveat to keep in mind is that your-code must not catch the InterruptedException used to trigger the TimeoutException. I use this for testing and it works well.

    See the Thread.interrupt() javadoc for additional caveats.

    You can see this code in use here.

提交回复
热议问题