2017-04-17 8 views
0

私は、複数のスレッドからアトム(マップ)のネストされたカウンタを更新しようとしていますが、予測できない結果を得ようとしています。スワップ! Clojure

(def a (atom {:id {:counter 0}})) 

    (defn upvote [id] 
    (swap! a assoc-in [(keyword id) :counter] (inc (get-in @a [(keyword id) :counter]))) 
) 

    (dotimes [i 10] (.start (Thread. (fn [] (upvote "id"))))) 
    (Thread/sleep 12000) 
    (prn @a) 

私はClojureにはとても新しいので何か間違っていますが何が分かりません。毎回異なる4〜10の結果を持つカウンタ値を表示しています。

私はアトミックカウンタ値を更新すると、このアプローチは、常にそれだけで失敗したときに再試行し、最終的にはそれがアップ投票のためだ10

に行くだろうと私に10のカウンタ値を与えることを期待同時に起動することができます。

ここで間違っていることが分かりますか?

+1

また、あなたが「ドン場合は、原子の代わりにエージェントを使用することを検討してください直ちに修正結果を知るためにスレッドを呼び出す必要があります。エージェントは暗黙的に変更をシリアル化するので、同期が外れることを心配する必要はありません。 – amalloy

答えて

5

コード内で非アトミックにアトムを更新しています。最初にその値を@aで取得し、swap関数を使用して適用します。値はその間で変化することがあります。

値を更新するためのアトミックな方法は、@を経由して前のアトム値を参照することなく、スワップ内の純粋な機能を使用することです:

(defn upvote [id] 
    (swap! a update-in [(keyword id) :counter] inc))