在Clojure改变与通勤:我做错了什么?

在Clojure改变与通勤:我做错了什么?,clojure,transactions,Clojure,Transactions,Clojure新手,我正在浏览优秀的“Clojure从头开始”帖子,并尝试了最后一个练习 当我将alter替换为communion时,总数不准确,但我不明白为什么 (我跳过了设置未来并调用它们的代码等) 使用trans-alter时,我得到了总和的4999950000(这是正确的预期值),而使用trans-conversion时,我每次得到的值不同,但高于预期值(例如4999998211) 我错过了什么?提前谢谢 通勤和改变本质上是做同样的事情,尽管在保证正确性方面通勤稍微宽松一些 Alter指

Clojure新手,我正在浏览优秀的“Clojure从头开始”帖子,并尝试了最后一个练习

当我将
alter
替换为
communion
时,总数不准确,但我不明白为什么

(我跳过了设置未来并调用它们的代码等)

使用
trans-alter
时,我得到了总和的
4999950000
(这是正确的预期值),而使用
trans-conversion
时,我每次得到的值不同,但高于预期值(例如
4999998211


我错过了什么?提前谢谢

通勤和改变本质上是做同样的事情,尽管在保证正确性方面通勤稍微宽松一些

Alter指示STM始终确保此代码一直运行,而不会从下面更改它使用的任何引用

Communite是一条指令,用于帮助STM决定何时需要中止事务,因为底层数据已从事务下更改

如果事务中的所有内容都是可交换的,那么即使某些数据发生了更改,也可以让该事务完成。在您的情况下,两项交易可能同时发生:

  • 抓住第一个号码
  • 从工作中删除相同的号码
  • 将相同的数字添加到结果中
  • 然后使用
    通勤
    指示STM这是正常的,它应该继续并提交事务
  • 得到错误的答案

  • 简言之,你要做的工作实际上不是一个交换运算。特别地,从列表中删除一个项目是不可交换的。如果你把任何一条通勤路线改成另一条,那么第四步就会将其中一条路线踢出,只允许其中一条路线完成。被踢出的那个将根据新数据重新运行,最终将得到正确的结果

    提示:不要在事务中添加一个和,而是尝试连接到一个列表,看看哪些数字实际上得到了和。谢谢,我尝试了,发现了重复的,相同的数字被添加了两次。
    (def work (ref (apply list (range 1e5))))
    (def sum (ref 0))
    
    (defn trans-alter [work sum]
      (dosync
       (if-let [n (first @work)]
         (do
           (alter work rest)
           (alter sum + n)
           (count @work))
         0)))
    
    (defn trans-commute [work sum]
      (dosync
       (if-let [n (first @work)]
         (do
           (commute work rest)
           (commute sum + n)
           (count @work))
         0)))