为什么Clojure的原子会互换!返回新值?

时间:2014-11-10 06:56:47

标签: clojure

大多数原子运算符在交换之前返回先前的值,例如C ++中的std::atomic::fetch_add。使用原子int作为从0开始的全局增加id是很自然的。为什么Clojure的原子返回交换的值?

(def global-counter (atom 0))
(defn next! [] (dec (swap! global-counter inc)))

有没有更好的方法在Clojure中创建一个从零开始的计数器?

3 个答案:

答案 0 :(得分:3)

反问题:你知道为什么std::atomic::fetch_add会返回交易前的价值吗? (我不是。)

调用swap!执行事务并返回其结果。在并发场景中,如果它返回事务前的值,获得事务结果的唯一确定性方法是重复事务内应用程序,例如: G。

(def pre-tx (std-swap! global-counter inc))
(def tx-result (inc pre-tx))

当然,相反的例子可以弥补交易前的价值。但是,在大多数情况下(以及您的示例情况 - 见下文),tx-result是与进一步参考相关的值。这就是为什么swap!被设计为直接返回它的原因。对于不同的要求,ref是合适的(除非使用atom,否则您必须使用compare-and-set!创建自己的自旋循环。

在您的示例中,next!应该在第一次调用时返回1,只要计数是给定示例,就没有理由dec 。计数始终以一个开头:如果算一,则总计数为1。如果next!曾返回0(虚构)last!将返回-1,则总计数无效。

答案 1 :(得分:2)

您可能希望使用java.util.concurrent.atomic.AtomicInteger来创建全局增加ID:

(def global-counter (AtomicInteger. 0))
(defn next! [] (.getAndIncrement global-counter))

答案 2 :(得分:2)

swap!允许您将任意函数应用于原子,并且您事先不知道结果是什么。如果swap!没有给你发布值,那么它就没用了;如果你想知道结果(或者有人可以在你揭穿它之前更新它),你必须创建一个deref它的交易。