Clojure

原子

原子提供了一种管理共享、同步、独立状态的方法。它们与引用和变量一样是一种引用类型。您可以使用 atom 创建一个原子,并使用 deref/@ 访问其状态。与引用和代理一样,原子也支持验证器。要更改原子的值,可以使用 swap!。还提供了一个低级别的 compare-and-set!。对原子的更改总是免于竞争条件。

与所有引用类型一样,原子的预期用途是保存 Clojure 的一个不可变数据结构。并且,类似于 ref 的 alter 和 agent 的 send,您可以通过对旧值应用函数来更改值。这是由 swap! 以原子方式完成的。在内部,swap! 读取当前值,将函数应用于它,并尝试将它 compare-and-set! 进去。由于另一个线程可能在期间更改了值,它可能需要重试,并且在自旋循环中执行此操作。最终效果是,该值将始终是将提供的函数应用于当前值的原子结果。但是,由于该函数可能会被多次调用,因此它必须没有副作用。

原子是一种有效的方式来表示一些永远不需要与任何其他状态协调的状态,并且您希望对它进行同步更改(与代理不同,代理是类似的独立状态,但异步)。典型的用法可能是用于记忆化。

(defn memoize [f]
  (let [mem (atom {})]
    (fn [& args]
      (if-let [e (find @mem args)]
        (val e)
        (let [ret (apply f args)]
          (swap! mem assoc args ret)
          ret)))))

(defn fib [n]
  (if (<= n 1)
    n
    (+ (fib (dec n)) (fib (- n 2)))))

(time (fib 35))
user=> "Elapsed time: 941.445 msecs"

(def fib (memoize fib))

(time (fib 35))

user=> "Elapsed time: 0.044 msecs"

创建原子: atom

检查原子: deref (另请参阅 @ 读取器 宏)

更改原子状态: swap! reset! swap-vals! reset-vals!

观察者: add-watch remove-watch