2

我正在为 Campfire 开发一个聊天机器人,它将当前用户列表保存在一个原子中,(defonce users (atom {})).

我最初选择这个引用类型是因为它很简单,到目前为止它运行良好,但可能需要改变。

  1. Campfire 向流式 API发送EnterMessage和事件。LeaveMessage我的机器人通过从 Campfire API 获取当前用户列表来对这些做出反应,然后使用新列表调用reset!atom users

  2. 那些相同的 Enter/Leave 事件会触发随机交互,例如从usersatom 中选择一个随机用户并向其提问。

问题

上面的数字 2 经常询问刚刚离开的用户,或者从不询问刚进入的用户,因为users原子还没有!reset。我想我需要使用 a ref,但这些文档说“作家永远不会阻止通勤者或读者。 ”问题是,我希望那个作家阻止我的读者,对吧?!

4

1 回答 1

3

refs 主要是为协调访问多个数据结构而设计的,如果您只有一个身份(用户列表),那么 refs 的主要优势对您来说并不是真正的优势,尽管它也不是真正的问题。Refs 也有成本,因为事务可能会运行不止一次,因此如果您的操作具有发送消息等副作用,那么消息可能会在事务重试时发送两次。您可以通过同时使用 ref 和代理来解决此问题,因为从事务发送到代理的消息保证只发送一次并且仅使用最终提交的值。

在您的情况下,您可以通过以下方式做得很好:

或者

  • 切换到参考
  • 使用代理将实际消息发送给用户。
  • 使用手表可以使这更简单,但不是必需的。

引用“作家永远不会阻止通勤者或读者”。尽管值得解释一下,但可能与您没有直接关系。在单个 ref 的情况下,仅读取 ref 值的线程从不等待,它获取当前值并继续。当有多个 ref 时,它可以在一个事务中读取它们,并保证它会从它们两者中获得一组一致的值,或者将重新运行,直到它确实获得一组一致的值。需要更新值的线程如果没有获得一组一致的值,同样需要重新运行,除非它们使用commute函数来更新它们,在这种情况下,STM 会知道即使提交新值也是安全的是不是某个其他线程也对该值进行了相同的(或可交换的)操作。

于 2012-10-03T18:56:02.700 回答