我正在阅读 Programming Clojure 一书。在解释alter
和STM时,他们说如果在更改期间,Clojure检测到来自事务外部的ref的更改,它将使用新值重新运行事务。如果是这种情况,我认为你传递的更新函数需要是纯粹的,但是文档中没有指出(并且在其他类似的情况下)。
我的假设是正确的吗?如果没有,STM如何重新应用该功能?如果它是正确的,那么您是否可以依靠文档告诉您何时可以产生副作用,何时不能?
答案 0 :(得分:8)
它不一定是纯粹的,它必须是idempotent。在实践中,这基本上是相同的。
此外,在STM之外看到它只需要是幂等的:如果您产生的唯一副作用是写入其他参考或(我认为)发送给代理,该操作将一直持续到您的交易为止成功了。
还有 的任何一种情况并非如此:只是,如果您的更新功能不纯,结果可能不是您所期望的。
编辑:dosync
的文档告诉您,正文中的任何表达式都可能被执行多次。如果不运行alter
,则无法运行dosync
,因此看起来您需要的所有文档都在那里。你想改变什么?
答案 1 :(得分:4)
正如旁注:
如果您需要执行诸如登录STM转换之类的副作用,您可以向代理发送消息以执行非幂等部分。仅在事务完成时才会调度发送给代理的消息,并且保证仅发送一次。
答案 2 :(得分:1)
Clojure中的一点是,当您处理事务时没有副作用,因为它们是一致的,并且当在更新共享值期间发现冲突时,该函数将重新运行(我更喜欢重试),否则它会成功地改变。 如果它必须重试,它将读取更新的值,因此没有副作用,你可以找到的问题是一个活锁,但它有一种受Clojure重试中的限制数控制。