commute

clojure.core

  • (commute ref fun & args)
Must be called in a transaction. Sets the in-transaction-value of
ref to:

(apply fun in-transaction-value-of-ref args)

and returns the in-transaction-value of ref.

At the commit point of the transaction, sets the value of ref to be:

(apply fun most-recently-committed-value-of-ref args)

Thus fun should be commutative, or, failing that, you must accept
last-one-in-wins behavior. commute allows for more concurrency than
ref-set.

1 Example top

  • user=> (def counter (ref 0))
    #'user/counter
    
    ;; deciding whether to increment the counter takes the terribly long time
    ;; of 100 ms -- it is decided by committee.
    user=> (defn commute-inc! [counter]
             (dosync (Thread/sleep 100) (commute counter inc)))
    #'user/commute-inc!
    user=> (defn alter-inc! [counter]
             (dosync (Thread/sleep 100) (alter counter inc)))
    #'user/alter-inc!
    
    ;; what if n people try to hit the counter at once?
    user=> (defn bombard-counter! [n f counter]
             (apply pcalls (repeat n #(f counter))))
    #'user/bombard-counter!
    
    ;; first, use alter.  Everyone is trying to update the counter, and
    ;; stepping on each other's toes, so almost every transaction is getting 
    ;; retried lots of times:
    user=> (dosync (ref-set counter 0))
    0
    user=> (time (doall (bombard-counter! 20 alter-inc! counter)))
    "Elapsed time: 2007.049224 msecs"
    (3 1 2 4 7 10 5 8 6 9 13 14 15 12 11 16 17 20 18 19)
    ;; note that it took about 2000 ms = (20 workers * 100 ms / update)
    
    ;; now, since it doesn't matter what order people update a counter in, we
    ;; use commute:
    user=> (dosync (ref-set counter 0))
    0
    user=> (time (doall (bombard-counter! 20 commute-inc! counter)))
    "Elapsed time: 401.748181 msecs"
    (1 2 3 4 5 9 10 6 7 8 11 15 13 12 14 16 19 17 18 20)
    ;; notice that we got actual concurrency this time.
Log in to add / edit an example.

See Also top

  • 0
    clojure.core/ref

    Creates and returns a Ref with an initial value of x and zero or mo

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/core.clj:2159 top

(defn commute
  "Must be called in a transaction. Sets the in-transaction-value of
  ref to:

  (apply fun in-transaction-value-of-ref args)

  and returns the in-transaction-value of ref.

  At the commit point of the transaction, sets the value of ref to be:

  (apply fun most-recently-committed-value-of-ref args)

  Thus fun should be commutative, or, failing that, you must accept
  last-one-in-wins behavior.  commute allows for more concurrency than
  ref-set."
  {:added "1.0"
   :static true}

  [^clojure.lang.Ref ref fun & args]
    (. ref (commute fun args)))
Vars in clojure.core/commute:
Used in 0 other vars

Comments top

No comments for commute. Log in to add a comment.