I have a system that consists of a map, of the rough form {1 [1 2 3] 2
[2 3 4]}. An update to the system chooses a couple random keys, looks
them up in the map, does some math with them, and writes two new
values. If one or both of the keys don't exist, they need to be
created and their values initialized.
My thought was to represent them as (ref {key1 (ref val1) k2 (ref
v2)...}), which according to my current understanding of the STM only
"locks" the map as a whole if a new key is being added, and otherwise
should only "lock" the val being accessed/updated. Atoms on the vals
aren't really an option, since the updates need to see a consistent
state between them.
However, it looks like I'm spending between 50-80% of my time in
clojure.lang.transaction.BlockAndBail, and the single-threaded version
takes ~25% less time than the concurrent version, even with just 2
threads, and even after giving the system time to "warm up" so it
should no longer be creating significant numbers of new keys.
I have a feeling that I'm grabbing the main ref on every read, and
causing all transactions to proceed serially. Can someone confirm my
suspicion, and is there good way to represent this kind of system in a
non-blocking manner? Finally, will having an atom, vs. a ref, guard
the overall map cause Bad Things to happen?
My code for get-or-set is:
(defn- get-or-set-nested-ref
"targ is of form (ref {key (ref val)}).
Check outside the transaction for index and deref. If it's not
there,
enter a transaction and check in a consistent context. If it's
there,
deref and return it; if not, initialize it to a ref to a default
value."
[targ index default-fn]
@(get @targ index
(dosync (if-let [r (get @targ index)] r
(-> (alter targ
assoc index (ref (default-fn)))
(get index))))))
The last wrinkle is that in the context of the update code, get-or-set-
nested-ref is always called inside a dosync block to begin with, so
the first deref always happens inside a transaction - this is why I
think an atom as the main guard might help, but I'm not sure how that
interacts with the STM as a whole or if there would be possibly
inconsistent edge cases.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en