2017-04-17 39 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))