使用clojure的stm作为一个被视为良好做法的全球国家?

时间:2012-10-29 22:45:34

标签: clojure

在我的大多数clojure程序中......以及我看到的其他一些clojure程序,原子中有某种全局变量:

(def *program-state* 
   (atom {:name  "Program"
          :var1  1
          :var2  "Another value"}))

这种状态偶尔会在代码中引用。

(defn program-name []
    (:name @*program-state*))

阅读这篇文章http://misko.hevery.com/2008/07/24/how-to-write-3v1l-untestable-code/让我重新思考全球状态但不知何故,即使我完全同意这篇文章,我认为可以在原子中使用哈希映射,因为它提供了一个用于操纵全局状态数据的通用接口(类似于使用不同的数据库来存储您的数据)。

我想就此事提出一些其他想法。

3 个答案:

答案 0 :(得分:2)

我认为拥有一个偶尔以交换方式更新的单一全球状态是可以的。当你开始有两个需要更新的全局状态并且线程开始使用它们进行通信时,我开始担心。

  • 保持当前全球用户的数量很好:
    • 任何线程都可以在任何时候加入或拒绝这一点而不会伤害另一个
    • 如果它从你的线程下变了,没有什么东西爆炸。
  • 维护日志目录是有问题的:
    • 当它发生变化时,所有线程都会停止写入旧的线程吗?
    • 如果两个线程发生变化,它们会收敛。
  • 使用它作为消息队列更加可疑:

答案 1 :(得分:2)

这种东西可以没问题,但它也常常是一种设计气味所以我会谨慎对待。

要考虑的事情:

  • 一致性 - 代码的一部分可以更改程序名称吗?如果是这样,那么program-name函数将从其他线程的角度来看表现不一致。不好!
  • 可测试性 - 这是否易于测试?更改程序名称的测试套件的一部分可以安全地与另一个读取名称的测试同时运行吗?
  • 多个实例 - 您是否希望应用程序的两个不同部分同时使用不同的程序名?如果是这样,这是一个强烈暗示,你的可变状态不应该是全局的。

需要考虑的替代方案:

  • 使用 ref代替原子,您至少可以确保事务中可变状态的一致性
  • 使用绑定,您可以将可变性限制为每个线程。这解决了大多数并发问题,并且在使用全局变量时可能会有所帮助,就像一组线程本地配置参数一样。
  • 尽可能使用不可变的全局状态。它确实需要变得可变吗?

答案 2 :(得分:1)

我认为拥有这样一个全局状态(在许多情况下它是必需的)是很好的但我会小心我的应用程序的核心逻辑具有将状态作为参数并返回更新状态的函数而不是直接访问全球状态。基本上我宁愿从几组函数中控制访问全局状态,我程序中的其他所有东西都应该使用这些方法来访问状态,因为这样可以抽象出状态实现,即最初我可以启动使用内存中的原子,然后可能会移动到某个持久存储。