【问题标题】:Clojure STM: non consistent removeClojure STM:不一致的删除
【发布时间】:2013-06-09 16:16:53
【问题描述】:

考虑一个非常简单的哈希表,其结构如下:

(defn make-hashtable
  [cap]
  (let 
    [tablesize (int (Math/ceil (* cap 1.30)))]
      {:tablesize tablesize
     :capacity cap
       :size (ref 0)
       :vector (vec (map (fn [_] (ref '())) (range tablesize)))
       :type :hashtable}))

我有它的基本操作,如putgetremove。我编写了一些测试来使用pcalls 并行测试它们。当我第一次开发一个在一个“thread”上运行的测试时,(即只使用一个函数来调用pcalls)并且它成功了,我必须假设问题不存在但remove函数不是线程-安全。

remove的实现如下:

(defn mht-remove
  [table key]
  (let [pos (table-pos table key)]
    (dosync 
      (let [bucket @((:vector table) pos)]
        (ensure (:size table))
        (ensure ((:vector table) pos))
        (defn equalskey?
          [x]
          (= (:key x) key))
        (when (some equalskey? bucket)
            (ref-set ((:vector table) pos) (remove equalskey? bucket))
            (alter (:size table) dec))))))

奇怪的是,即使只有一个元素的桶没有被删除。这很奇怪,因为只有向量的元素是 refs,而不是整个向量。 问题:为什么这段代码不是线程安全的,我可能做错了什么?


注意:我知道很多人会尝试评论这个应用程序的设计,但这不是我感兴趣的答案。我想了解clojure 的 STM 而不是编写纯函数式代码。

【问题讨论】:

    标签: concurrency clojure transactions stm


    【解决方案1】:

    您似乎不能在dosyncblock 内执行defdefn,因为它是全局副作用,因此会干扰您的交易。即使我不完全理解,除了根据文档不允许副作用之外,这就是搞砸一切的原因。

    感谢 Freenode 的 #clojure 上的人

    【讨论】:

    • 不仅如此:不要在函数内部使用defdefn,句号。即使没有dosync,它也会弄乱你的单线程代码。
    • 使用 'let' 而不是 'def':clojure fns 是值,因此您可以将它们分配给临时绑定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-10
    相关资源
    最近更新 更多