2017-04-17 40 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

還要考慮使用的試劑代替的原子的,如果你不t需要調用線程立即知道修改的結果。代理隱式序列化修改,所以您不必擔心不同步。 – amalloy

回答

5

您正在代碼中非原子地更新原子。您首先通過@a得到它的值,然後使用swap函數應用它。該值可能會在兩者之間改變。

原子方式更新該值是使用交換內的純函數,不經由@參照前一原子值:

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