我正在寻找一种在Clojure中定期调用函数的简单方法.
JavaScript setInterval
有我想要的那种API.如果我在Clojure中重新构想它,它看起来像这样:
(def job (set-interval my-callback 1000)) ; some time later... (clear-interval job)
出于我的目的,我不介意这是创建一个新线程,在线程池或其他东西中运行.时机也是准确的并不重要.事实上,提供的时间段(以毫秒为单位)可能只是一个呼叫结束和下一个呼叫开始之间的延迟.
我对此进行了编码,其界面略微修改,而不是原始问题中指定的界面.这就是我想出来的.
(defn periodically [fn millis] "Calls fn every millis. Returns a function that stops the loop." (let [p (promise)] (future (while (= (deref p millis "timeout") "timeout") (fn))) #(deliver p "cancel")))
欢迎反馈.
如果你想要非常简单
(defn set-interval [callback ms] (future (while true (do (Thread/sleep ms) (callback))))) (def job (set-interval #(println "hello") 1000)) =>hello hello ... (future-cancel job) =>true
再见.
最简单的方法是在一个单独的线程中有一个循环.
(defn periodically [f interval] (doto (Thread. #(try (while (not (.isInterrupted (Thread/currentThread))) (Thread/sleep interval) (f)) (catch InterruptedException _))) (.start)))
您可以使用Thread.interrupt()
以下命令取消执
(def t (periodically #(println "Hello!") 1000)) ;; prints "Hello!" every second (.interrupt t)
你甚至可以future
用来包裹循环并future-cancel
阻止它.
另一种选择是使用java.util.Timer的schedualeAtFixedRate方法
编辑 - 在单个计时器上复用任务,并停止单个任务而不是整个计时器
(defn ->timer [] (java.util.Timer.)) (defn fixed-rate ([f per] (fixed-rate f (->timer) 0 per)) ([f timer per] (fixed-rate f timer 0 per)) ([f timer dlay per] (let [tt (proxy [java.util.TimerTask] [] (run [] (f)))] (.scheduleAtFixedRate timer tt dlay per) #(.cancel tt)))) ;; Example (let [t (->timer) job1 (fixed-rate #(println "A") t 1000) job2 (fixed-rate #(println "B") t 2000) job3 (fixed-rate #(println "C") t 3000)] (Thread/sleep 10000) (job3) ;; stop printing C (Thread/sleep 10000) (job2) ;; stop printing B (Thread/sleep 10000) (job1))
这就是我如何使用停止通道执行core.async版本.
(defn set-interval [f time-in-ms] (let [stop (chan)] (go-loop [] (alt! (timeout time-in-ms) (do (<! (thread (f))) (recur)) stop :stop)) stop))
和用法
(def job (set-interval #(println "Howdy") 2000)) ; Howdy ; Howdy (close! job)
Clojure还有很多调度库:(从简单到非常先进)
在-AT
chime (core.async集成)
单调
石英岩
直接来自at-at的github主页的例子:
(use 'overtone.at-at) (def my-pool (mk-pool)) (let [schedule (every 1000 #(println "I am cool!") my-pool)] (do stuff while schedule runs) (stop schedule))
使用(every 1000 #(println "I am cool!") my-pool :fixed-delay true)
,如果你想任务结束之间一秒钟的延迟和明年的开始,而不是两次启动之间.