Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with...

66
Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM 1 Thursday, May 20, 2010

Transcript of Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with...

Page 1: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Stefan Tilkov | innoQ

Concurrent Programming with Clojure

Functional Programming meets the JVM

1Thursday, May 20, 2010

Page 2: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Stefan Tilkov

[email protected]://www.innoq.com/blog/st/

@stilkov

2Thursday, May 20, 2010

Page 3: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://rest-http.info

3Thursday, May 20, 2010

Page 4: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

SoftwareArchitekTOURMichael Stal - Christian Weyer -

Markus Völter - Stefan Tilkov

http://heise.de/developer/podcast

4Thursday, May 20, 2010

Page 5: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://www.innoq.com

5Thursday, May 20, 2010

Page 6: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

27.04.10 14:17http://upload.wikimedia.org/wikipedia/en/1/1a/Clojure-glyph.svg

Page 1 of 1

6Thursday, May 20, 2010

Page 7: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Clojure 27.04.10 14:17http://upload.wikimedia.org/wikipedia/en/1/1a/Clojure-glyph.svg

Page 1 of 1

A practical Lisp variant for the JVM Functional programming

Dynamic Typing Full-featured macro system

Concurrent programming supportBi-directional Java interop

Immutable persistent data structures

7Thursday, May 20, 2010

Page 8: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Lisp??

8Thursday, May 20, 2010

Page 9: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Lots of irritating silly parentheses?

9Thursday, May 20, 2010

Page 10: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://lemonodor.com/archives/2007/10/youre_doing_it_wrong.html

10Thursday, May 20, 2010

Page 11: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://lemonodor.com/archives/2007/10/youre_doing_it_wrong.html

11Thursday, May 20, 2010

Page 12: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://xkcd.com/297/

12Thursday, May 20, 2010

Page 13: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://www.flickr.com/photos/nicolasrolland/3063007013/

13Thursday, May 20, 2010

Page 14: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://www.tbray.org/ongoing/When/200x/2008/09/25/-big/R0010774.jpg.html

Rich Hickey

14Thursday, May 20, 2010

Page 15: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Intro

15Thursday, May 20, 2010

Page 16: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Clojure Environment

Clojuresque (Gradle)

Leiningen

16Thursday, May 20, 2010

Page 17: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Data structuresNumbers 2 3 4 0.234

3/5 -2398989892820093093090292321

Strings "Hello" "World"

Characters \a \b \c

Keywords :first :last

Symbols a b c

Regexps #"Ch.*se"

Lists (a b c)((:first :last "Str" 3) (a b)

Vectors [2 4 6 9 23][2 4 6 [8 9] [10 11] 9 23]

Maps {:de "Deutschland", :fr "France"}

Sets #{"Bread" "Cheese" "Wine"}

17Thursday, May 20, 2010

Page 18: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Syntax

18Thursday, May 20, 2010

Page 19: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

“You’ve just seen it” – Rich Hickey

19Thursday, May 20, 2010

Page 20: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Syntax(def my-set #{:a :b :c :c :c}) ;; #{:a :b :c}(def v [2 4 6 9 23])(v 0) ;; 2(v 2) ;; 6

(def people {:pg "Phillip", :st "Stefan"})(people :st) ;; "Stefan"(:xyz people) ;; nil

(+ 2 2) ;; 4(class (/ 4 3)) ;; clojure.lang.Ratio(* (/ 4 3) 3) ;; 3  

(format "Hello, %s # %d" "world" 1)

20Thursday, May 20, 2010

Page 21: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Syntax

; (a 2 3)(quote (a 2 3)) ;; (a 2 3)'(a 2 3) ;; (a 2 3)

; Evaluation     (eval '(format "Hello, %s" "World"))(eval (read-string "(+ 2 2)"))

(format "Hello, %s # %d" "world" 1); "Hello, World # 1"

(apply str ["Hello, %s # %d" "world" 1])

21Thursday, May 20, 2010

Page 22: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Functions(fn [x] (format "The value is %s\n" x));; user$eval__1706$fn__1707@390b755d

((fn [x] (format "The value is %s\n" x)) "Hello");; "The value is Hello"

(def testfn (fn [x] (format "The value is %s\n" x)))              (testfn "Hello")

(defn testfn [x] (format "The value is %s\n" x))(testfn "Hello")

22Thursday, May 20, 2010

Page 23: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Functions

(defn even [x] (= 0 (rem x 2))) (even 4) ;; true         (def even-alias even)(even-alias 2) ;; true

(defn every-even? [l] (every? even l))(every-even? '(2 4 6 8 9)) ;; false(every? #(= 0 (rem % 2)) '(2 4 6 8 9)) ;; false

23Thursday, May 20, 2010

Page 24: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Functions(defn make-counter [initial-value]  (let [current-value (atom initial-value)]    (fn []      (swap! current-value inc))))

(def counter1 (make-counter 0))(counter1) ;; 1(counter1) ;; 2

(def counter2 (make-counter 17))(counter1) ;; 3(counter2) ;; 18(counter1) ;; 4(counter2) ;; 19

24Thursday, May 20, 2010

Page 25: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Recursion

(defn reduce-1 [f val coll]  (if (empty? coll) val    (reduce-1 f (f val (first coll)) (rest coll))))

(reduce-1 + 0 [1 2 3 4]) ;; 10(reduce-1 + 0 (range 5)) ;; 10(reduce-1 + 0 (range 50)) ;; 1225(reduce-1 + 0 (range 50000)) ;; java.lang.StackOverflowError

25Thursday, May 20, 2010

Page 26: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

(defn reduce-2 [f val coll]  (if (empty? coll) val    (recur f (f val (first coll)) (rest coll))))

(defn reduce-1 [f val coll]  (if (empty? coll) val    (reduce-1 f (f val (first coll)) (rest coll))))

Recursion

(reduce-2 + 0 [1 2 3 4]) ;; 10(reduce-2 + 0 (range 5)) ;; 10(reduce-2 + 0 (range 50)) ;; 1225(reduce-2 + 0 (range 50000)) ;; 1249975000

26Thursday, May 20, 2010

Page 27: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Example(ns sample.grep  "A simple complete Clojure program."  (:use [clojure.contrib.io :only [read-lines]])  (:gen-class))

(defn numbered-lines [lines]   (map vector (iterate inc 0) lines))

(defn grep-in-file [pattern file]  {file (filter #(re-find pattern (second %)) (numbered-lines (read-lines file)))})

(defn grep-in-files [pattern files]  (apply merge (map #(grep-in-file pattern %) files)))

(defn print-matches [matches]  (doseq [[fname submatches] matches, [line-no, match] submatches]    (println (str fname ":" line-no ":" match))))            (defn -main [pattern & files]  (if (or (nil? pattern) (empty? files))    (println "Usage: grep <pattern> <file...>")    (do       (println (format "grep started with pattern %s and file(s) %s" pattern (apply str (interpose ", " files))))      (print-matches (grep-in-files (re-pattern pattern) files))      (println "Done."))))

27Thursday, May 20, 2010

Page 28: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Macros

(log "Hello, World") Tue Apr 27 19:06:43 CEST 2010: Hello, World

(def *debug* true)

(defn log [msg]  (if *debug* (printf "%s: %s\n" (java.util.Date.) msg)))

(log (format "Hello, World %d" (* 9 9))))Tue Apr 27 19:06:45 CEST 2010: Hello, World 81

28Thursday, May 20, 2010

Page 29: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Macros

(defmacro log [body]  (if *debug* `(printf "%s: %s\n" (java.util.Date.) ~body)))

(log "Hello, World") Tue Apr 27 19:06:43 CEST 2010: Hello, World

(macroexpand '(log "Hello, World"))

(def *debug* true)

(if user/*debug* (printf "%s: %s\n" (java.util.Date.) "Hello, World"))

(macroexpand '(log (format "Hello, World %d" (* 9 9))))(if *debug*   (printf "%s: %s\n" (java.util.Date.) (format "Hello, World %d" (* 9 9))))

29Thursday, May 20, 2010

Page 30: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Macros

(defmacro with-debug [body]  `(binding [*debug* true]     ~body))

Tue Apr 27 19:22:35 CEST 2010: Hello, WorldTue Apr 27 19:22:35 CEST 2010: Clojure rocks

(with-debug  (log "Hello, World")  (log "Clojure rocks"))

(binding [*debug* false]  (log "Hello, World"))

30Thursday, May 20, 2010

Page 31: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Macros(defmacro with-debug [body]  `(binding [*debug* true]     ~body))

(macroexpand '(binding [*debug* true]  (log "Hello, World")))

(let*[] (clojure.core/push-thread-bindings (clojure.core/hash-map (var *debug*) true))(try  (log "Hello, World")  (finally (clojure.core/pop-thread-bindings))))

31Thursday, May 20, 2010

Page 32: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Lots of other cool stuff

Persistent data structuresSequences

Support for concurrent programmingDestructuring

List comprehensionsMetadata

Optiional type informationMultimethods

Pre & Post ConditionsProtocols (1.2)

Extensive core and contrib libraries…

32Thursday, May 20, 2010

Page 33: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

State

33Thursday, May 20, 2010

Page 34: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

4711: Personfirst: Johnlast: Smith

0815: Personfirst: Janelast: Doe

The Problem!

34Thursday, May 20, 2010

Page 35: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Immutabilityuser> (def v (apply vector (range 10)))

user> (assoc v 1 99)[0 1 2 3 4 5 6 7 8 9]user> v#'user/v

[0 99 2 3 4 5 6 7 8 9]

[0 1 2 3 4 5 6 7 8 9]user> v

user> (def v2 (assoc v 1 99))

user> v2#'user/v2

[0 99 2 3 4 5 6 7 8 9]

35Thursday, May 20, 2010

Page 36: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

user> (def v (apply vector (range 10)))user> (def v2 (assoc v 1 99))

9

4

7

0 1 6 83 5

2

v

99

v2

36Thursday, May 20, 2010

Page 37: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Persistent Data Structures

Pure functional programming modelEfficient implementation

Structural sharingThread-safe

Iteration-safeBased on Bit-partioned hash tries

“Transient” data structures if needed

37Thursday, May 20, 2010

Page 38: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Performance Guarantees

hash-map sorted-map hash-set sorted-set vector queue list lazy seq

conj near-constant

logarithmic

near-constant

logarithmic

constant (tail)

constant (tail)

constant (head)

constant (head)

assoc near-constant

logarithmic

- - near-constant

- - -

dissoc near-constant

logarithmic

- - - - - -

disj - - near-constant

logarithmic

- - - -

nth - - - - near-constant

linear linear linear

get near-constant

logarithmic

near-constant

logarithmic

near-constant

- - -

pop - - - - constant (tail)

constant (head)

constant (head)

constant (head)

peek - - - - constant (tail)

constant (head)

constant (head)

constant (head)

count constant constant constant constant constant constant constant linear

38Thursday, May 20, 2010

Page 39: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Sequences

Standard API for everything sequencable

CollectionsStringsNative Java arraysjava.lang.IterableAnything that supportsfirst, rest, cons

39Thursday, May 20, 2010

Page 40: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Sequences

Standard API for everything sequencable“Lazy” sequences

(def n (iterate (fn [x] (+ x 1)) 0))(def fives (map #(* 5 %) n))(take 10 fives)

40Thursday, May 20, 2010

Page 41: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Sequences

Standard API for everything sequencable“Lazy” sequencesExtensive library

applybutlastconcatconscycledistinctdoalldorundoseqdropdrop-lastdrop-whileempty?every?ffirstfile-seqfilterfirstfnextfor

interleaveinterposeintointo-arrayiterateiterator-seqkeyslastlazy-catlazy-seqline-seqmapmapcatnextnfirstnnextnot-any?not-emptynot-every?nth

nthnextpartitionpmaprangere-seqreduceremoverepeatrepeatedlyreplacereplicaterestresultset-seqreverserseqrsubseqsecondseqseq?seque

setsomesortsort-bysplit-atsplit-withsubseqtaketake-nthtake-whileto-array-2dtree-seqvalsvecwhen-firstxml-seqzipmap…

41Thursday, May 20, 2010

Page 42: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Concurrency Support

42Thursday, May 20, 2010

Page 43: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Core Ideas

Everything immutableShared state for reading

No changes to shared stateIsolated threads

Re-use of platform facilitiesJava Integration

(java.util.concurrent.Callable)

43Thursday, May 20, 2010

Page 44: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

def & binding

(def some-var 10)(binding [some-var 30]  (println some-var)) ;; 30

(def some-var 10)(println some-var) ;; 10

(binding [some-var some-var]  (println some-var) ;; 10  (set! some-var 30)  (println some-var)) ;; 30

44Thursday, May 20, 2010

Page 45: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Atoms

(def a (atom "Initial Value")) (println @a) ;; "Initial Value"

(swap! a #(apply str (reverse %)))(println @a) ;; "eulaV laitinI"

(swap! a #(apply str (reverse %)))(println @a) ;; "Initial Value"

45Thursday, May 20, 2010

Page 46: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Atoms(defn run-thread-fn [f]   (.start (new Thread f)))

(defn add-list-item [coll-atom x]  (swap! coll-atom #(conj % x)))

(def int-list (atom ())) ;; ()(run-thread-fn #(add-list-item int-list 5)) ;; (5)(run-thread-fn #(add-list-item int-list 3)) ;; (3 5)(run-thread-fn #(add-list-item int-list 1)) ;; (1 3 5)

(def int-list (atom ())) ;; ()(let [run-fn (fn [x] (run-thread-fn #(add-list-item int-list x)))]  (doall (map run-fn (range 100)))) ;; (98 97 96 ... 0)

46Thursday, May 20, 2010

Page 47: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Refs

(defn make-account   [balance owner]  {:balance balance, :owner owner})

(defn withdraw [account amount]  (assoc account :balance (- (account :balance) amount)))

(defn deposit [account amount]  (assoc account :balance (+ (account :balance) amount)))

47Thursday, May 20, 2010

Page 48: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Refs

(defn init-accounts []  (def acc1 (ref (make-account 1000 "alice")))  (def acc2 (ref (make-account 1000 "bob")))  (def acc3 (ref (make-account 1000 "charles"))))

(defn transfer  [from to amount]  (dosync   (alter from withdraw amount)   (alter to deposit amount)))

48Thursday, May 20, 2010

Page 49: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Refs(init-accounts)

(do (run-thread-fn #(transfer acc1 acc2 100)) (transfer acc3 acc1 400))

acc1: {:balance 1000, :owner "alice"}acc2: {:balance 1000, :owner "bob"}acc3: {:balance 1000, :owner "charles"}

acc1: {:balance 1300, :owner "alice"}acc2: {:balance 1100, :owner "bob"}acc3: {:balance 600, :owner "charles"}

49Thursday, May 20, 2010

Page 50: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Refs

(defn slow-transfer  [from to amount]  (dosync   (sleep 1000)   (alter from withdraw amount)   (alter to deposit amount)))

(do (run-thread-fn #(slow-transfer acc1 acc2 100)) (transfer acc3 acc1 400))

acc1: {:balance 1600, :owner "alice"}acc2: {:balance 1200, :owner "bob"}acc3: {:balance 200, :owner "charles"}

acc1: {:balance 1300, :owner "alice"}acc2: {:balance 1100, :owner "bob"}acc3: {:balance 600, :owner "charles"}

50Thursday, May 20, 2010

Page 51: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Software Transactional Memory (STM)

Multi-version concurrency control (MVCC)Atomic changes to multiple refs

Non-blocking, retry-based“Read committed”

Can't help with non-pure functionsWorks with atoms and agents

ref-set altercommuteensurederef/@ throw

51Thursday, May 20, 2010

Page 52: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Software Transactional Memory

ref-set

alter

commute

ensurederef/@ Reads value of reference, blocks none

Reads value of reference, blocks writers

Reads value of reference, blocks none,delayed write, last writer wins

Changes reference to new value, blocks writers

Atomically reads, computes, sets reference value, blocks writers

throw Rolls back transaction

52Thursday, May 20, 2010

Page 53: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

AgentsAsynchronous execution

Run on java.util.concurrent thread pool

await await-forsend-offsendagent

(let [my-agent (agent 0)      slow-fn  (fn [x]                 (sleep 1000)                 (inc x))]  (send my-agent slow-fn)  (println @my-agent)  (sleep 2000)  (println @my-agent));; 0;; 1

deref/@

53Thursday, May 20, 2010

Page 54: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Agents

await

await-for

send-off

send

agent

deref/@

Creates agent with initial value

Dispatch function to agent for execution

Dispatch long-running function

Read agent value

Wait for agent to execute function(s) dispatched from current thread

Same as await, but with timeout

54Thursday, May 20, 2010

Page 55: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Validators(def some-var 10)

(set-validator! #'some-var #(< % 100))

(def some-var 101) ;; Invalid reference state ;; [Thrown class java.lang.IllegalStateException]

(def some-var)(defn limit-validator [limit]  (fn [new-value]    (if (< new-value limit)       true      (throw (Exception. (format "Value %d is larger than limit %d" new-value limit))))))

(set-validator! #'some-var (limit-validator 100))(def some-var 101);; Value 101 is larger than limit 100;; [Thrown class java.lang.Exception]

55Thursday, May 20, 2010

Page 56: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Watchers(def *a* (atom 0))(def *events* (atom ()))

(defn log-event  [coll s]  (swap! coll conj s))

(log-event *events* "some event") ;; ("some event")(log-event *events* "yet another event") ;; ("yet another event" "some event")

(defn log-value-change  [key ref old new]   (if (= key :log)    (log-event *events* (format "value of %s changed from %d to %d" ref old new))))

(log-value-change :log 'x 0 1);; ("value of x changed from 0 to 1" "yet another event" "some event")(add-watch a :log log-value-change)(swap! a inc) ;; 1

(deref *events*) ;; ("value of clojure.lang.Atom@59829c6b changed from 0 to 1";; "value of x changed from 0 to 1" "yet another event" "some event")

56Thursday, May 20, 2010

Page 57: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Futures & Promisesuser> (doc future)-------------------------clojure.core/future([& body])Macro  Takes a body of expressions and yields a future object that will  invoke the body in another thread, and will cache the result and  return it on all subsequent calls to deref/@. If the computation has  not yet finished, calls to deref/@ will block.

user> (doc promise)-------------------------clojure.core/promise([])  Alpha - subject to change.  Returns a promise object that can be read with deref/@, and set,  once only, with deliver. Calls to deref/@ prior to delivery will  block. All subsequent derefs will return the same delivered value  without blocking.

57Thursday, May 20, 2010

Page 58: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

thread-localglobal shared

def bindingset!

single multiple

sync async

atom

dosyncref

agent

58Thursday, May 20, 2010

Page 59: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Summary

Built on immutablity from the ground upPowerful collections

Extensive sequence libraryBuilt-in concurrency primitives

59Thursday, May 20, 2010

Page 60: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

01 2010start date 0905

01 2010start date 05

01 201009

60Thursday, May 20, 2010

Page 61: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Java Integration

61Thursday, May 20, 2010

Page 62: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Clojure → Java(new java.lang.String "Hello")(java.lang.String. "Even quicker")(java.io.File/separator)(import '(java.io InputStream File)) (File/separator)(. System/out println "Hello")(.println System/out "Hello")

(every? #(instance? java.util.Collection %) '([1 2] '(1 2) #{1 2}));; true

(defn blank? [s] (every? #(Character/isWhitespace %) s))(blank? "some string") ;; false(blank? "") ;; true

62Thursday, May 20, 2010

Page 63: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Clojure ↔ Java

(Collections/sort java-collection                  (make-comparator #(. %1 compareTo %2)))

;; #<Vector [Alpha, Beta, Gamma]>

(defn make-comparator [compare-fn]     (proxy [java.util.Comparator] []       (compare [left right] (compare-fn left right))))

(import '(java.util Vector Collections))

(def java-collection (Vector.))(doto java-collection  (.add "Gamma")  (.add "Beta")  (.add "Alpha"));; #<Vector [Gamma, Beta, Alpha]>

63Thursday, May 20, 2010

Page 64: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Clojure ← Javapackage com.innoq.test;public interface ClojureInterface {    String reverse(String s);}

package com.innoq.test;public class ClojureMain {    public static void main(String[] args) {        ClojureInterface cl = new ClojureClass();        System.out.println("String from Clojure: " + cl.reverse("Hello, World"));    }}

(ns com.innoq.test)

(gen-class  :name   com.innoq.test.ClojureClass  :implements [com.innoq.test.ClojureInterface]  :prefix class-)

(defn class-reverse  [this s]  (apply str (reverse s)))

64Thursday, May 20, 2010

Page 65: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

http://clojure.org/

http://peepcode.com/products/functional-programming-with-clojure

http://vimeo.com/channels/fulldisclojure

#clojure freenode

[email protected]

build.clojure.org

http://en.wikibooks.org/wiki/Clojure

http://technomancy.us/136

Books

http://stuartsierra.com/

http://www.bestinclass.dk/index.php/blog/

http://technomancy.us/

http://kotka.de/blog/

http://blog.fogus.me/

BlogsCore

Screencasts

http://www.assembla.com/wiki/show/clojure/Getting_Started

http://github.com/relevance/labrepl

65Thursday, May 20, 2010

Page 66: Concurrent Programming with Clojure - INNOQ · Stefan Tilkov | innoQ Concurrent Programming with Clojure Functional Programming meets the JVM Thursday, May 20, 2010 1

Q&A

Stefan [email protected]

http://www.innoq.com/blog/st/Twitter: stilkov

http://xkcd.com/224/

66Thursday, May 20, 2010