在clojure的计时器?

Nik*_*Nik 8 timer clojure

我想知道是否有广泛的计时器解决方案.

我想写一个简单的游戏引擎,它会每20分钟处理一次用户输入(或者 20ms(或任何其他时间段后)执行一次动作)并基本上通过事务更新"全局"状态,而且我打算使用futures这个解决方案应该能够处理并发警告.

你能给我一个建议吗?

mik*_*era 13

你实际上有两个不同的问题.

首先是计时器的问题.你有很多选择:

  • 启动一个在操作之间休眠的线程,例如 (future (loop [] (do-something) (Thread/sleep 20) (when (game-still-running) (recur))))
  • 使用Java TimerTask - 从Clojure轻松调用
  • 使用像我的小实用程序任务库,包括用于重复任务的DSL
  • 使用您正在使用的任何游戏引擎的计时器功能 - 其中大多数提供了一些设置游戏循环的工具

我可能只是使用简单的线程选项 - 它很容易设置,如果你需要,可以在以后轻松破解更多功能.

第二个问题是处理游戏状态.这实际上是棘手的问题,你需要围绕你正在制作的特定类型的游戏设计它,所以我只是给出一些建议:

  • 如果您的游戏状态是不可变的,那么您将获得很多优势:您的渲染代码可以在游戏更新计算下一个游戏状态时独立绘制当前游戏状态.不可变性有一些性能成本,但如果你可以使其工作,并发性优势是巨大的.我的迷你Clojure游戏(Ironclad和Alchemy)都使用这种方法
  • 您应该尝试将游戏状态存储在单个顶级var中.我发现这比在不同的vars上分割游戏状态的不同部分更好.这也意味着你并不真正需要基于ref的事务:原子或代理通常会做到这一点.
  • 您可能希望实现需要由游戏状态更新功能按顺序处理的事件队列.如果您有多个并发事件源(例如,玩家操作,计时器滴答,网络事件等),这一点尤为重要.


小智 7

现在我认为核心/异步是一个很好的选择,因为

  • 当涉及到可以分成使用渠道进行通信的活动的复杂任务时,它可以很好地扩展
  • 避免绑定活动到一个线程

这是草图

(require '[clojure.core.async :refer [go-loop]])
(go-loop []
  (do
    (do-something ...)
    (Thread/sleep 1000)
    (recur))))
Run Code Online (Sandbox Code Playgroud)

  • 使用`(<!(timeout 2000))`而不是`Thread/sleep`并引用`<!`和`timeout` (6认同)

Ben*_*aum 5

此解决方案假设您在JVM上编写Clojure.像这样的东西可以工作:

(import '(java.util TimerTask Timer))

(let [task (proxy [TimerTask] []
             (run [] (println "Here we go!")))]
  (. (new Timer) (schedule task (long 20))))
Run Code Online (Sandbox Code Playgroud)

  • @jig,在JVM上考虑使用`ScheduledExecutorService`:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html.Timer有几个缺点,执行器服务没有. (4认同)