在Clojure中定时执行代码

18

在Clojure中,让代码定时运行的最佳方式是什么?我目前使用的是java.util.concurrent.ScheduledExecutorService,但那是Java - 是否有一种Clojure的方式来安排代码以延迟、可取消的方式运行?我看到的所有Clojure代码示例都使用Thread/sleep,这似乎也太Java了。

4个回答

22

非常值得查看Overtone的源代码,特别是用于在特定时间安排事件的代码

它是一个音乐合成系统,所以你必须希望他们有正确的定时代码!

此外,他们已将定时代码分离到单独的项目中(overtone/at-at),以便您可以轻松导入。它为底层Java库(即ScheduledThreadPoolExecutor和其它)提供了一个良好的Clojure包装器。语法如下:

;; run some-function every 500ms
(every 500 some-function)

您还可以在特定时间安排事件:

;; run some-other-function 10 seconds from now
(at (+ 10000 (now)) some-other-function)

聪明人想法相似,也许 :-) 如果您有好的补充,请贡献给 overtone/at-at,如果我们能够在 Clojure 中开发一个出色的时间库,那将是非常棒的! - mikera
嗯,不完全一样...函数名相同但方法不同。我的代码依赖于clj-time...at-at 看起来不错 - 谢谢! - Hendekagon
虽然这不完全是我需要的,因为我还需要在特定日期的特定时间完成某些事情。 - Hendekagon
非常好的答案,我正在考虑在我的一个项目中需要类似的东西,一定会去看看 overtone/at-at - djhworld
overtone/at-at 在过去几个月似乎有些被忽视了,这个 fork 可能会很有意思:https://github.com/silasdavis/at-at - berdario

19

从Clojure网站http://clojure.org/concurrent_programming获取以下信息:

在所有情况下,Clojure不会替换Java线程系统,而是与其一起工作。Clojure函数是java.util.concurrent.Callable,因此它们可以与Executor框架等一起使用。

听起来你已经以正确的方式进行了操作。

(import 'java.util.concurrent.Executors)
(import 'java.util.concurrent.TimeUnit) 
(.scheduleAtFixedRate (Executors/newScheduledThreadPool 1) 
  #(println "Hello") 0 5 TimeUnit/SECONDS)

好的,但是感觉使用Java来完成如此普通的事情有点傻。 - Hendekagon
2
Clojure 的原则之一是拥抱主机平台(如果它足够强大)。在这种情况下,Clojure 的答案不太可能少于一个表达式。 - Arthur Ulfeldt
2
Interop很棒,当然使用Java对于这个很有意义,但出于美观原因,我至少希望有一个包装器。 - Hendekagon
在我看来,Java 并不够强大:ScheduledExecutorService 只有 3(4)个方法,其中只有一个方法重载以接受 Callable 而不是 Runnable,这会导致您计划的函数中的异常被静默地吞噬(甚至没有将任何内容打印到 stderr!)... 显然,我并不真正关心重复计划函数的结果,所以我并不需要整个 Callable... 我看了一下 at-at,不幸的是它似乎也没有在其 fn 参数中包装 try-catch-printstacktrace - berdario

1

0

"tools.timer" 库是一个 Java Timer 包装器:https://github.com/Ruiyun/tools.timer

它非常容易使用:

(use 'ruiyun.tools.timer)
(run-task! #(println "Say hello every 5 seconds.") :period 5000)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接