Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Clojure向量原子中删除第一项并返回它_Clojure - Fatal编程技术网

从Clojure向量原子中删除第一项并返回它

从Clojure向量原子中删除第一项并返回它,clojure,Clojure,我有一个原子包裹着一个项目向量: (def items (atom [1 2 3 4])) 我想自动删除第一项并将其返回。此代码说明了逻辑: (let [x (first @items)] (swap! items #(subvec % 1)) x) 但是当许多线程相互竞争时,上面的代码是不正确的。读取和更新之间存在竞争条件 如中所述,原子用于不协调的同步访问。我希望这可以用原子而不是ref来实现,因为原子更简单 是否有一种只使用原子而不使用参考物的解决方案?(我将尝试使用手表,看看

我有一个原子包裹着一个项目向量:

(def items (atom [1 2 3 4]))
我想自动删除第一项并将其返回。此代码说明了逻辑:

(let [x (first @items)]
  (swap! items #(subvec % 1))
  x)
但是当许多线程相互竞争时,上面的代码是不正确的。读取和更新之间存在竞争条件

如中所述,原子用于不协调的同步访问。我希望这可以用原子而不是ref来实现,因为原子更简单

是否有一种只使用原子而不使用参考物的解决方案?(我将尝试使用手表,看看效果如何。)如果您的答案坚持需要ref,请您解释一下为什么需要ref,即使在需要“协调同步访问多个身份”时建议使用ref(与上面的链接相同)


这与其他相关问题不同,例如和,因为我想更新向量原子并返回值。

带有
比较数据集的自旋循环用于
交换一个原子。Clojure还提供较低级别的
比较和设置用于原子,您可以使用它进行自己的自旋循环,并返回旧值和新值

(defn swap*!
  "Like swap! but returns a vector of [old-value new-value]"
  [atom f & args]
  (loop [] 
    (let [ov @atom 
          nv (apply f ov args)]
      (if (compare-and-set! atom ov nv)
        [ov nv]
        (recur)))))

(defn remove-first-and-return [atom]
  (let [[ov nv] (swap*! atom subvec 1)]
    (first ov)))

如果需要使用atom,请使用本地封装的atom来存储获胜事务的in-transaction值的第一个元素

(let [f-atom (atom nil)]
  (swap! items-atom #(do (reset! f-atom (first %)) 
                         (rest %)))
  @f-atom)
或者,使用
ref
dosync
事务块实现相同的功能:

(dosync
  (let [f (first @items-ref)]
    (alter items-ref rest)
    f)))

这里,如果事务因并行写入操作成功而失败,则事务不会返回,也不会对ref产生影响,直到可以重试,以便读写操作不会被另一个写入操作中断。

这不是此用例的解决方案,但对其他人来说可能是这样


您可以在atom上创建一个手表,它将发送一个包含新旧值的事件。

我的解决方案是在包含值的元数据中存储所需的任何返回值。我不知道这有多惯用,它显然只适用于实现
IMeta
接口的类

(defn pop-head!
  [a]
  (-> (swap! a #(with-meta (subvec % 1) {:head (% 0)}))
      (meta)
      :head))
这得益于
交换
(def a (atom [1 2 3 4]))
(pop-head! a) ;; => 1
(pop-head! a) ;; => 2
(pop-head! a) ;; => 3
(pop-head! a) ;; => 4
(pop-head! a) ;; => IndexOutOfBoundsException...

是的,你可能想处理那个案子

自从添加了
交换VAL
在Clojure 1.9中,您可以使用
(ffirst(swap vals!items rest))
从向量返回第一个元素,并在单个操作中更新原子。

我认为执行此操作所需的长度表明这超出了原子的预期用途。:)“但是,很好的破解。”我也这么认为——直到我看到它也依赖于
。compareAndSet
的循环。我现在认为这是对原子的一种很好的利用。为什么要为这个简单的用例设置一个ref呢?看起来Prismatic已经有一段时间了,使用了更好的
交换对in。对于这种不使用另一个atom存储in事务值的方法,到Prismatic Pimping的
交换对的链接当前为+1。也许一个有名称空间的kw会使解决方案更加通用。为了记录在案,在Clojure Google小组中有一个类似的讨论,这可能是一个有趣的问题。好问题!!!!!!你添加了标签…但你的问题与此有关吗?(Web提要格式)