Reputation: 3247
I am trying to track requests to a server, and do something when the data is ready. I have the following code which seems to work but I wonder if there's a better way to do it - in particular I find it strange that, in the future below, I'm dereferencing a promise inside dereferencing an atom, with the atom possibly changing state.
(def requests (atom {:a (promise) :b (promise)}))
(future @(:b @requests) (println "b is ready"))
(swap! requests assoc :c (promise))
(deliver (:b @requests) 100)
>> b is ready
Thank you,
Upvotes: 2
Views: 204
Reputation: 92117
The main issue I see with this approach is that you put this promise inside an atom, but if anyone ever actually mutates the atom to contain a different promise, your program will break: the watcher will be waiting on a promise that nobody else has a reference to. Instead, I'd put the promise inside some immutable structure shared by the two parts of the code that need to communicate.
You could be a bit fancier and use a core.async channel instead of a promise, but if you only ever need to deliver a single value, a promise is fine.
Upvotes: 1
Reputation: 16060
Atoms were designed to solve exactly this problem:
Internally, swap! reads the current value, applies the function to it, and attempts to compare-and-set! it in. Since another thread may have changed the value in the intervening time, it may have to retry, and does so in a spin loop.
So you are safe here as long as two threads don't use the same key for the map (:a :b :c).
Upvotes: 2