我正在阅读Programming Clojure这本书。在解释alter
和 STM 时,他们说如果在更改期间,Clojure 检测到来自事务外部对 ref 的更改,它将使用新值重新运行事务。如果是这种情况,我会想象您传入的更新函数需要是纯的,但文档中没有说明(并且在其他类似情况下也是如此)。
那么我的假设正确吗?如果不是,STM如何重新应用该功能?如果它是正确的,是不是你不能依靠文档告诉你什么时候可以有副作用,什么时候不能?
它不一定是纯的,它只是必须是幂等的。在实践中,这基本上是一样的。
此外,它仅在 STM 之外必须是幂等的:如果您产生的唯一副作用是写入某个其他 ref 或(我认为)发送给代理,则该操作将一直保持到您的事务成功为止。
它也不是必须是这些东西中的任何一个:只是,如果你的更新函数不是纯的,结果可能不是你所期望的。
编辑:dosync
的文档告诉您,正文中的任何表达式都可能多次执行。不运行 a就无法alter
运行 a dosync
,因此看起来您需要的所有文档都在那里。你想改变什么?
顺便说一句:
如果您需要执行副作用,例如登录您的 STM 事务,您可以向代理发送消息以执行非幂等部分。发送给代理的消息仅在事务完成时发送,并且保证只发送一次。
Clojure 中的要点是,在处理 Transactions 时没有副作用,因为它们是一致的,并且在更新 Shared Value 过程中发现冲突时,函数会重新运行(我更喜欢重试),否则会成功提交更改。如果它必须重试,它会读取更新的值,所以没有副作用,你可以找到一个活锁的问题,但它是受 Clojure 重试次数限制的控制。