Overview of Concurrency in clojure

Liverpool Clojure Dojo 
3rd June 2013








@doppioslash
http://gplus.to/gattoclaudia

the old way

The Problems: 
Deadlocks
Race conditions

The Old Solution:
Locking
    The Culprit:

    Mutable State

    The Clojure Way


    Avoid mutable state:
    Immutable data structures
    Side effects free

    Where state cannot be eliminated:
    Software Transactional Memory

    ...and Alfred North Whitehead's ideas.

    Software Transactional Memory

    Changes of state are wrapped in transactions, which ensure:

      • Atomicity
    either all changes of a transaction are applied or none.
      • Consistency
    only valid changes are committed.
      • Isolation
    no transaction sees the effect of other transactions.
      • Durability
    changes are persistent.

    IDENTITY and value

    Mutable state as an illusion:
    it's actually a causally-linked succession of immutable values created by applying a function to the current value.
      • Value
    an immutable magnitude, quantity, number, or composite of these
      • Identity

    a series of causally related states over time
      • State
    value of an identity at a moment in time
      • Time
    relative ordering of causal values.

    immutable

        
    Applying a function that modifies a data structure will return a new data structure rather than modifying the old one
       
    => (def a-map {:key "value"}) #'user/a-map    => (assoc a-map :another-key "more values"){:key "value", :another-key "more values"}=> a-map{:key "value"} 

    Reference types


    vars


    refs


    atoms


    agents

    vars

    Per-thread local state.

    The root binding is seen by all threads.

    Rebound values are only seen by the local thread.

    Since Clojure 1.3 needs ^:dynamic

    Demonstration of thread-locality.

    VARS

    Rebinding a var
     => (def ^:dynamic a-var 42)
    #'user/a-var
    => a-var
    42=> (def ^:dynamic a-var 43)
    #'user/a-var
    => a-var
    43

    vars

    Using binding
     => (defn print-var 
    =>   ([] (println a-var))
    =>   ([prefix] (println prefix a-var)))
    #'user/print-var
    => (bindind [a-var 44]
    =>   (print-var))
    44
    nil

    VARS

    Demonstration that vars are thread-local
     => (import java.lang.Thread)
    java.lang.Thread
    => (defn with-spawned-thread [fun]
    =>   (.start (java.lang.Thread. fun)))
    #'user/with-spawned-thread
    => (do
    =>   (binding [a-var "rebound a-var"]
    =>     (with-spawned-thread
    =>       (fn [] (print-var "bg: ")))
    =>     (print-var "fg1: "))
    =>   (print-var "fg2: "))
    bg: 42
    fg1:  rebound a-var
    fg2: 42
    nil

    REFS

    Synchronous and coordinated

    multiple refs can be updated in one trasaction

     wrapped in dosync

     more than one change can be executed in the same transaction.

    REFS

    To mutate: alter and ref-set
     => (def a-ref (ref 42))
    #'user/a-ref
    => (ref-set a-ref 43)
    IllegalStateException No transaction running  clojure.lang.LockingTransaction.getEx (LockingTransaction.java:208)
    => (dosync (ref-set a-ref 43))
    43
    => (deref a-ref)
    43
    => @a-ref
    43
    => (dosync (alter a-ref inc))
    44

    ATOMS

    Indipendent state
    Uncoordinated
    Atomic
    Synchronous
    State is mutated using a function
    makes it safe to retry

    atoms

    To mutate: swap! and reset!
     => (def an-atom (atom 42))
    #'user/an-atom
    => @an-atom
    42
    => (swap! an-atom inc)
    43
    => @an-atom
    43
    => (swap! an-atom (fn [old] 44))
    44
    => (reset! an-atom 42)
    42
    => @an-atom
    42

    atoms

    Update the value of an item inside a collection inside an atom
     => (def vector-atom (atom []))
    #'user/vector-atom
    => (swap! vector-atom conj 42)
    [42]
    => (swap! vector-atom conj 43)
    [42 43]
    => (swap! vector-atom assoc-in [0] inc)
    [43 43]

    AGENTS

    Asynchronous

    Uncoordinated

    Can be accessed from any thread

    On error state the agent must be reset

    AGENTS

    To mutate send and send-off
     => (def an-agent (agent 42))
    #'user/an-agent
    => @an-agent
    42
    => (send an-agent inc)
    #<Agent@492f96c3: 43>

    Clojure ants

    MORE

    Futures
    Promises
    Pmap
    Delays


    References

    Avout: distributed state in Clojure
    Pluralsight Clojure Concurrency course
    Clojuredoc's Concurrency and Parallelism in Clojure

    Concurrency in Clojure

    By Claudia Doppioslash

    Concurrency in Clojure

    • 4,256