I'm writing a Mandelbrot Set implementation, and to speed up finding out which points go off into infinity, I decided to try using an ExecutorService
to check the points in parallel.
Basically the plan is:
Atom
wrapping a vector
as they are producedMy problem is with the last point. How can I safely grab the previous results from an atom, and reset it?
I thought about the simple way of just:
(def draw-queue-A (atom []))
(defn grab-and-clear-queue []
(let [results @draw-queue-A]
(reset! draw-queue-A [])
results))
But this looks unsafe. If something is added between the dereference and the reset!
, it will be lost.
The atrocious abomination I've settled on at the moment is:
(defn grab-and-clear-queue []
(let [results (atom [])]
(swap! draw-queue-A
(fn [res] (reset! results res)
[]))
results))
But using an atom just to retrieve the results seems ridiculous.
How can I sanely retrieve the contents of an atom, and reset it without potentially losing any results?
One simple answer is to use a Clojure ref
instead of an atom
. It allows you to lock the value for more than a single function invocation (unlike 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)))
with results:
-------------------------------------
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) => []
Other options would include using a queue from either clojure.core.async
or a simple Java thread-safe queue.
Depending on the format of your problem, you could also make use of a Python-style generator function as described here.