Multiple updates with atoms
- Introducing enhancements to
swap!, such as memoize, can help make it fast. Lets you do bigger values, longer updates, while still keeping state in a regular atom.
- Megalomania: Introducing multiple updates with an
update-insfunction that uses
assoc-in. By introducing a function called
swap-ins!, can also swap using
- It's really a half-baked STM, where you have to declare every dependency your code may have upfront. Not as powerful as STM, but helped to think about paths as alternative to discrete identities. What's the mutable part of your state? Let's try that in STM...
- Thinking of a situation where the world is in a single ref. Memoize doesn't work, because no single function encompasses the full transaction.
- But there's lock striping used by
java.util.concurrent(especially ConcurrentHashMap): A fixed pool of locks, each item guarded by one of the locks. Items with different locks won't have concurrency issues. If you want to access the nth item, compute
n mod n-locksto get the corresponding lock.
- Ref striping: Put the whole data structure (e.g. vector) in a single ref, and then have guards - refs too, similarly to striped locking. Under the root ref, always commute. Add dummy actions on the guard(s), so that the transaction will take the "lock" into account.
- Tried first hacking the STM to support this -> fail.
- A naive
alter-nth: Takes a ref, an index into the vector, the function and its arguments. Calls
update-inin the specified index, function, anr arguments.
indexed-ref. It is a ref, which knows that it works with a vector. Associcate a guard key with the guard refs in the metadata of the indexed ref.
alter-nthgets the guards, then gets the nth card using
ref-sets the guard to
nil(it's a no-op but lets STM know that this ref is in the transaction). Then it does the actual operation with
commute. The naive version used
alter, but the ref-striped version can use
commutebecause the guard enforces ordering.
- On this you can have
- From nth to in - extending this to anything associative. Need to deal with paths again.
[:a :c]should be concurrent, but should prevent independent updates for
- One guard for each prefix,
[:a :b :c]. All prefix guards are ensured, and the full path is
ref-set, so that it will block.
commute-in. All have the same semantics as the naive impls (e.g.
update-in), but allow for more concurrency.
- For back-compatibility with existing codebases, megaref has drop-in replacements for
ref-set. The functions work with both refs and megarefs.
- Subrefs: Mutable view of a bigger ref:
(subref parent-ref path). Allows migration from code with a bunch of refs to some megrefs, because you can still use the code that deals with the single ref.
set-option!allow tuning at runtime: Number of guards, history, validator.
- No upfront decision about the splitting of state.
- Performance is comparable to plenty-of-refs when not CPU bound. Snapshotting is cheap (demoed Hickey's ants, where originally getting the current state required a transaction because of the many refs. Started to fail with lots of concurrency. Megarefs only needed
- If your code is CPU-bound the megaref overhead will start to show up.
- Further ideas: Allocation profiling, Tuning path hash function - more guards for hot paths? self-tuning? Doing this for agents.
Know Your AngularJS Inside Out
Build Your Own AngularJS helps you understand everything there is to understand about AngularJS (1.x). By creating your very own implementation of AngularJS piece by piece, you gain deep insight into what makes this framework tick. Say goodbye to fixing problems by trial and error and hello to reasoning your way through them