Multithreading 如何使用Clojure管理对状态的并发访问和对HTTP客户端的调用

Multithreading 如何使用Clojure管理对状态的并发访问和对HTTP客户端的调用,multithreading,clojure,state,agent,Multithreading,Clojure,State,Agent,我正在做一个编程游戏来自学Clojure。 基本上,它是一个通过HTTP轮询客户端的JSON操作的服务器 目前,我将整个游戏状态作为一个向量原子,包含单个玩家的状态映射。 服务器将游戏更改更新为这些玩家状态,并轮询客户端以获得他们想要的下一个操作 我读过一些关于原子、试剂和其他的东西,但我还没有完全弄明白 我的问题是:我应该如何更改数据结构或其存储机制,以及如何进行轮询和其他更新,以便它们不会相互干扰或同时干净地运行 我发现投票可能应该由代理完成(对吗?)。也许我应该添加一个监视程序,将返回的值

我正在做一个编程游戏来自学Clojure。 基本上,它是一个通过HTTP轮询客户端的JSON操作的服务器

目前,我将整个游戏状态作为一个向量原子,包含单个玩家的状态映射。 服务器将游戏更改更新为这些玩家状态,并轮询客户端以获得他们想要的下一个操作

我读过一些关于原子、试剂和其他的东西,但我还没有完全弄明白

我的问题是:我应该如何更改数据结构或其存储机制,以及如何进行轮询和其他更新,以便它们不会相互干扰或同时干净地运行

我发现投票可能应该由代理完成(对吗?)。也许我应该添加一个监视程序,将返回的值更新到服务器中管理的播放器状态

我还认为,为了实现这一点,我应该将游戏状态更改为地图,这样我就可以轻松访问各个玩家的状态

(def game-state {"player1" {:stuff {...} :action a1}
                 "player2" {:stuff {...} :action a3}})
游戏状态是否应该由玩家状态作为原子组成,如下所示:

{“player1”原子
“player2”atom}

。。。还是别的什么

除此之外,还有一个visualiser HTML/JavaScript(AngularJS)页面,定期从服务器轮询游戏状态

目前,由于我没有线程化轮询,当一个速度较慢的客户机思考其下一个操作(测试用例)时,其他一切都被卡住了

任何关于如何在Clojure中正确执行此操作的意见和建议都将不胜感激


另外,我没有包括数据库,因为我觉得不需要在游戏会话中存储数据,但如果使用数据库使这更容易或更正确,我可能会使用一些内存数据库。

我终于有时间做这件事了

我最终把游戏状态变成了一张地图。我把它作为一个原子留下了

对于客户端轮询,我定义了一个线程池

(def ^ExecutorService poller-thread-pool (Executors/newCachedThreadPool))
由于Clojure函数是可运行的,我只需调用从客户端请求操作的函数,然后更新特定玩家的游戏状态

(let [player-keys-and-states (seq game-state)
      threads (map request-and-update player-keys-and-states)
      tasks (map #(.submit poller-thread-pool %) threads)]
    (dorun tasks))
因为map返回一个惰性序列,所以启动每个线程/函数都需要Dorun

编辑


我必须改变它,这样只有一个线程更新游戏状态中的值,因为当那些轮询器线程也改变它时,它会以奇怪的状态结束。我为轮询者添加了一个新的映射以进行更新,然后让“主”线程读取该映射,并用其中的值更新游戏状态。

我实际上会使用
core.async
来处理类似的问题,并使用纯香草原子来管理状态。使用尽可能少的原子;在这种情况下,您只需要一个:
def game state(atom{:player1…:player2…})
代理,一般来说,只有当您希望它们封装由线程管理的状态时才是正确的工具——如果您只需要一个线程,只需使用一个线程;Rich自己也说过,当Java标准库线程和线程池抽象最适合于一项任务时,使用Java标准库线程和线程池抽象是正确和惯用的;它花费了大量的时间和精力在习语和为特定的工作选择合适的工具上。谢谢你的提示。事实上,我正在等待最新版的《Clojure的欢乐》出版。。。