我正在经历Clojure Koans,现在我正在玩原子。我的问题与Koans无关,而是一般的问题。
考虑Koans的以下(缩短)示例:
(def atomic-clock (atom 0))
(meditations
(= 1 (do
(swap! atomic-clock inc)
@atomic-clock)))
交换文档!声明它应用于(在这种情况下为inc
)的函数可以被多次调用,因此该函数应该没有副作用。
显然,inc
没有副作用,但不是幂等的。这是否意味着,上述断言实际上可能仍然失败?即在函数确实被多次调用的情况下,原子的值会增加多次?
答案 0 :(得分:8)
如果有多个线程竞争修改Atom,则可以多次调用传递给swap!
的函数。然而,只要它没有副作用,只有最终调用的返回才会反映在Atom的因果历史中。 1
以下是一种可能的情况:
主题1尝试(swap! atomic-clock inc)
。
线程2尝试相同。
线程2设法首先执行swap!
。
线程1尝试对原子进行比较和交换并失败,因为它原始值的概念现已过时。
线程1重试并成功提交。
这里有三次调用inc
,两次调用线程1,一次调用线程2.
inc
不是幂等的事实不是问题。
1 抽象地考虑; Clojure实际上并不存储Atoms的历史信息。
答案 1 :(得分:1)
不,因为该函数将使用原始值多次调用。如果交换成功,则不会使用函数生成的新值再次调用该函数。 “可能再次被调用”的情况是,原子的值已经被程序的另一部分改变了,因此重试了交换。只要您为相同的参数返回相同的结果,这很好 - 但是,如果您正在从流中读取数据并将其粘贴在原子中,那么这将是有问题的。
答案 2 :(得分:1)
不,这实际上意味着如果您在原子上交换多个线程,该函数可能会重试以使用正确的值。
描述以下执行:
线程1:
atomic-clock
0 atomic-clock
atomic-clock
线程2:
atomic-clock
仍为0 atomic-clock
atomic-clock
错误应为2 为了使用原子值调用函数,必须读取当前值。
但是如果在另一个线程中修改了当前值,则整个读取/更新过程必须重试,因此再次调用您的函数。
意思是如果你的函数发射火箭,它将发射两枚火箭,即使它第一次用0调用并返回1,第二次用1调用并返回2。