获取原子的状态,并以原子方式重置它

Car*_*ate 6 atomic clojure

我正在编写一个Mandelbrot Set实现,并且为了加快找出哪些点进入无穷大,我决定尝试使用ExecutorService并行检查点.

基本上该计划是:

  • 计算我需要找到的所有点
  • 给每个点服务
  • 让服务将其结果转储到生成Atom包装a vector
  • 让绘图代码定期获取生成的结果,并清除队列

我的问题是最后一点.我怎样才能安全地从原子中获取先前的结果重置它?

我想到了简单的方法:

(def draw-queue-A (atom []))

(defn grab-and-clear-queue []
  (let [results @draw-queue-A]
    (reset! draw-queue-A [])
    results)) 
Run Code Online (Sandbox Code Playgroud)

但这看起来不安全.如果在取消引用和之间添加了某些内容reset!,它将会丢失.

我此刻已经解决的残暴憎恶是:

(defn grab-and-clear-queue []
  (let [results (atom [])]
    (swap! draw-queue-A
           (fn [res] (reset! results res)
                     []))
    results))
Run Code Online (Sandbox Code Playgroud)

但是使用原子来检索结果似乎很荒谬.

我怎样才能理智地检索原子的内容,重置它而不会丢失任何结果?

Jos*_*osh 6

目前有一张处理这个要求的JIRA票.在此期间,这可以做你想要的,并且类似于补丁中的内容,尽管我只浏览了代码:

(defn reset-return-old!
  [atm new-value]
  (let [old-value @atm]
    (if (compare-and-set! atm old-value new-value)
      (do
        (.notifyWatches atm old-value new-value)
        old-value)
      (recur atm new-value))))
Run Code Online (Sandbox Code Playgroud)

我们依赖于CAS语义,就像那样swap!.我们有效地旋转以保证我们不会在读取和CAS之间中断(尽管我认为这仍然是ABA问题的牺牲品,但我认为在这种情况下这并不重要).

我正在通知上面的手表 - 如果你没有,为了你的目的,你可以消除它和do块进一步简化.


Ala*_*son 2

一个简单的答案是使用 Clojureref而不是atom. 它允许您锁定多个函数调用的值(与 不同swap):

(ns tst.clj.core
  (:use clj.core clojure.test tupelo.test)
  (:require [tupelo.core :as t] ))
(t/refer-tupelo)
(t/print-versions)

(def results (ref []))
(future
  (doseq [i (range 10)]
    (dosync
      (Thread/sleep 20)
      (alter results t/append i))))

(defn get-and-clear []
  (dosync
    (let [curr-results @results]
      (ref-set results [])
      curr-results)))

(doseq [i (range 10)]
  (Thread/sleep 50)
  (spyx (get-and-clear)))
Run Code Online (Sandbox Code Playgroud)

结果:

-------------------------------------
   Clojure 1.8.0    Java 1.8.0_111
-------------------------------------
(get-and-clear) => [0 1]
(get-and-clear) => [2 3]
(get-and-clear) => [4]
(get-and-clear) => [5 6]
(get-and-clear) => [7]
(get-and-clear) => [8 9]
(get-and-clear) => []
(get-and-clear) => []
(get-and-clear) => []
(get-and-clear) => []
Run Code Online (Sandbox Code Playgroud)

其他选项包括使用来自任一队列clojure.core.async简单的 Java 线程安全队列。

根据问题的格式,您还可以使用此处所述的 Python 样式生成器函数。

  • 听起来你应该将这些持续的反对票视为鼓励你改进的信号,@AlanThompson,而不是作为某种迫害阴谋。显然我不是唯一一个认为您的某些答案毫无帮助的人。我赞成这一点,因为 tupelo 的使用(尽管仍然令人烦恼和分散注意力)是偶然的:算法的核心仅依赖于 clojure.core 中的内容,并且得到了很好的解释。 (3认同)