Clojure concurrency overview

28

description

Clojure, concurrency basics, atoms, vars, agents, refs.

Transcript of Clojure concurrency overview

Page 1: Clojure concurrency overview
Page 2: Clojure concurrency overview

Agenda

-Overview-Clojure features-Concurrent programming-Vars-Refs and STM approach-Atoms-Agents

Page 3: Clojure concurrency overview

Overview

Rich Hickeyhttps://twitter.com/#!/richhickey

-about 2.5 years working on Clojure-first public release at 2007-interview: http://www.simple-talk.com/opinion/geek-of-the-week/rich-hickey-geek-of-the-week/

Page 4: Clojure concurrency overview

What is Clojure?

Clojure is a dynamic, LISP-like programming language that runs on the JVM

Page 5: Clojure concurrency overview

How does it look? Exactly! Like LISP

Page 6: Clojure concurrency overview

A form is a list where the first symbol in the list has to be a special word that the compiler can understand - usually the name of a function

Page 7: Clojure concurrency overview

Clojure Features

● Functional○ Immutable, persistent data structures○ Functions are objects

● Lisp● Hosted on JVM

○ the same memory model○ garbage collector○ etc

● Supporting Concurrency ● Open source

Page 8: Clojure concurrency overview

Clojure Features

● Dynamic development○ REPL (read-eval-print-loop), on-the-fly

compilation to JVM bytecode● Full set of immutable, extensible, read-only

data structures:○ lists○ maps○ sets○ vectors

● Macros

Page 9: Clojure concurrency overview

Clojure Features

Java interop

● Call java-methods, access fields● Functions implement java.util.concurrent.

Callable (defn func (smthng)) ● Proxy interfaces/classes● Primitive types - int, long, byte, Char, String etc● Clojure data structures implement Collection, Iterable,

Comparable etc

Page 10: Clojure concurrency overview

Concurrent programming

● Things are happening at the same time● Number of CPU is growing fast

Page 11: Clojure concurrency overview

Concurrent programming problems

Visibility problem● Multiple threads use shared data● 2 or more threads are trying to

change the same data at the same time

Page 12: Clojure concurrency overview

Concurrent programming problems

Basic solution is● locks● synchronized access● only one thread can have

lock, others blocks ● But it requires additional efforts

○ thread-coordination○ avoiding deadlocks

Page 13: Clojure concurrency overview

Concurrent programming problems

Access problem● several threads are trying to

access and change the same shared data at the same time

● write/read at the same time● readers block readers

Page 14: Clojure concurrency overview

Clojure way

● There is no any possibility to change data by direct access. All data structures are immutable, remember?

● Only read, if we add element - new data structure will be created.

● No locks● No access problems

Page 15: Clojure concurrency overview

But what if we really want change

data in Clojure?This opportunity is also

provided by the language! All hard work done for us.

Page 16: Clojure concurrency overview

Reference types

● Vars● Refs● Atoms● Agents

Page 17: Clojure concurrency overview

Vars

● Reference to mutable storage location ● Dynamically rebound on a per-thread basis● Functions are vars, so they can be dynamically rebound too● Ensure safe use via thread-isolation

(def x 5) // root-binding(x) // 5....(binding [x 20] (+ x 1)) // 21 ....(x) // 5 again, not changed

Page 18: Clojure concurrency overview

Changing Vars

(set! var-name new-value)● cannot change root-binding● works only in thread-local context (in "binding")

(def x 5) // root-binding(set! x 7) // exception will be thrown....(binding [x 20] (println (+ x 1)) // 21 (set! x 10) (+ x 5)) // 15....(x) // 5 again, not changed

Page 19: Clojure concurrency overview

Refs

● Based on Software Transactional Memory (STM)● Change the value by applying a function to old value ● Refs can be changed within a transaction only ● Transactions will be retried automatically if conflict happens● To make changes code must be surrounded with (dosync

...)● All changes are atomic

Page 20: Clojure concurrency overview

Refs

(def r (ref '(1 2 3))) (deref r) // list (1 2 3) (dosync // transaction begins .... (alter r // change ref! (fn [_] '(10 9 8)) ... ) // transaction ends (deref r) // list (10 9 8)

Page 21: Clojure concurrency overview

Refs lifecycle

(def r (ref '(1 2 3))) (deref r) (dosync .... (alter r (fn [_] '(10 9 8)) ... ) (deref r)

if any other transaction commutes - this transaction is repeated

Otherwise, that's ok and programs continues execution

Page 22: Clojure concurrency overview

Atoms

● Way to manage shared state synchronously�● Change the value by applying a function to old value● This is done in an atomic manner by function swap!�● Internally, swap! reads the current value, appliesthe

function to it, and attemprs to call compare-and-set! for this atom

Page 23: Clojure concurrency overview

Atoms best practices by Rich Hickey

(defn memoize [f] (let [mem (atom {})] (fn [& args] (if-let [e (find @mem args)] (val e) (let [ret (apply f args)] (swap! mem assoc args ret) ret)))))

Page 24: Clojure concurrency overview

Atoms best practices by Rich Hickey

(defn fib [n] (if (<= n 1) n (+ (fib (dec n)) (fib (- n 2))))) (time (fib 35))user=> "Elapsed time: 941.445 msecs" (def fib (memoize fib)) (time (fib 35)) user=> "Elapsed time: 0.044 msecs"

Page 25: Clojure concurrency overview

Agents

● Asynchronous changing. They are not blocking main execution, return immediately

● Change the value by applying a function to old value● Agent action dispatches take the

form (send agent fn args*)● �If other actions try to change data - they will be added to

the queue

Page 26: Clojure concurrency overview

Agents

(def a (agent 5)) // create agent(deref a) // 5

(send a (fn [old-val] (+ old-val 5)))(deref a) // may be 5, or may be 10(Thread/sleep 1000)(deref a) // 10

Page 28: Clojure concurrency overview

Q&A