Clojure的功能应该交换!适用于幂等?

时间:2013-12-28 18:58:17

标签: clojure swap

我正在经历Clojure Koans,现在我正在玩原子。我的问题与Koans无关,而是一般的问题。

考虑Koans的以下(缩短)示例:

(def atomic-clock (atom 0))

(meditations
    (= 1 (do
        (swap! atomic-clock inc)
            @atomic-clock)))

交换文档!声明它应用于(在这种情况下为inc)的函数可以被多次调用,因此该函数应该没有副作用。

显然,inc没有副作用,但不是幂等的。这是否意味着,上述断言实际上可能仍然失败?即在函数确实被多次调用的情况下,原子的值会增加多次?

3 个答案:

答案 0 :(得分:8)

如果有多个线程竞争修改Atom,则可以多次调用传递给swap!的函数。然而,只要它没有副作用,只有最终调用的返回才会反映在Atom的因果历史中。 1

以下是一种可能的情况:

  1. 主题1尝试(swap! atomic-clock inc)

  2. 线程2尝试相同。

  3. 线程2设法首先执行swap!

  4. 线程1尝试对原子进行比较和交换并失败,因为它原始值的概念现已过时。

  5. 线程1重试并成功提交。

  6. 这里有三次调用inc,两次调用线程1,一次调用线程2.

    inc不是幂等的事实不是问题。


    1 抽象地考虑; Clojure实际上并不存储Atoms的历史信息。

答案 1 :(得分:1)

不,因为该函数将使用原始值多次调用。如果交换成功,则不会使用函数生成的新值再次调用该函数。 “可能再次被调用”的情况是,原子的值已经被程序的另一部分改变了,因此重试了交换。只要您为相同的参数返回相同的结果,这很好 - 但是,如果您正在从流中读取数据并将其粘贴在原子中,那么这将是有问题的。

答案 2 :(得分:1)

不,这实际上意味着如果您在原子上交换多个线程,该函数可能会重试以使用正确的值。

描述以下执行:

线程1:

  • 阅读atomic-clock 0
  • inc atomic-clock
  • 使用1
  • 更新atomic-clock

线程2:

  • 阅读atomic-clock仍为0
  • inc atomic-clock
  • 使用1 ==>更新atomic-clock错误应为2

为了使用原子值调用函数,必须读取当前值。

但是如果在另一个线程中修改了当前值,则整个读取/更新过程必须重试,因此再次调用您的函数。

意思是如果你的函数发射火箭,它将发射两枚火箭,即使它第一次用0调用并返回1,第二次用1调用并返回2。