Clojure

アトム

アトムは、共有され、同期され、独立した状態を管理する方法を提供します。 refやvarと同様に参照型です。 atomを使用してアトムを作成し、deref/@を使用してその状態にアクセスできます。 refやエージェントと同様に、アトムはバリデータをサポートします。 アトムの値を変更するには、swap!を使用できます。 低レベルのcompare-and-set!も提供されています。 アトムの変更は、常に競合状態がありません。

すべてのリファレンス型と同様に、アトムの意図された用途は、Clojureの不変データ構造の1つを保持することです。 また、refのalterやエージェントの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!

バリデータ: set-validator! get-validator

ウォッチャー: add-watch remove-watch