;;;; Snippet #1 user> (def atm (atom "physikalische Atmosphäre")) #'user/atm user> (deref atm) "physikalische Atmosphäre" user> (reset! atm "Pascal") "Pascal" user> @atm "Pascal" ;;;; ;;;; Snippet #2 (def koffer (atom "Ich packe meinen Koffer und nehme mit: ")) user> @koffer "Ich packe meinen Koffer und nehme mit: " (defn packe-ein-thread [ding sleep] (.start (Thread. (fn [] (Thread/sleep sleep) (swap! koffer str ding ", "))))) (defn koffer-packen [] (packe-ein-thread "Sammeltasse" 2000) (packe-ein-thread "Kulturbeutel" 1500) (packe-ein-thread "Zappaplatte" 1000) (packe-ein-thread "Schweinehälfte" 500) (packe-ein-thread "Klopfsauger" 100)) user> (koffer-packen) nil user> @koffer "Ich packe meinen Koffer und nehme mit: Klopfsauger, Schweinehälfte, Zappaplatte, Kulturbeutel, Sammeltasse, " ;;;; ;;;; Snippet #3 (def countdown (atom 1000)) (def aufrufe (atom 0)) (defn tick [akt-wert] (swap! aufrufe inc) (dec akt-wert)) user> (dotimes [_ 1000] (.start (Thread. #(swap! countdown tick)))) nil user> @countdown 0 user> @aufrufe 1076 ;;;; ;;;; Snippet #4 (def lotto-tipp (atom [])) (defn weitere-lotto-zahl [] (let [z (+ 1 (rand-int 49)) bislang @lotto-tipp] (Thread/sleep (rand-int 200)) (when (< (count bislang) 6) (println "evtl kommt" z "dazu" (compare-and-set! lotto-tipp bislang (conj bislang z)))))) (defn lotto-generator [] (while (< (count @lotto-tipp) 6) (.start (Thread. weitere-lotto-zahl)))) user> @lotto-tipp [] user> (lotto-generator) ;; Ausgabge gekuerzt und zwei Ausgaben pro Zeile evtl kommt 40 dazu true evtl kommt 25 dazu true evtl kommt 7 dazu true evtl kommt 37 dazu false evtl kommt 23 dazu false evtl kommt 8 dazu false evtl kommt 8 dazu false evtl kommt 3 dazu false evtl kommt 35 dazu true evtl kommt 21 dazu false evtl kommt 3 dazu false evtl kommt 49 dazu false evtl kommt 21 dazu true evtl kommt 44 dazu false evtl kommt 16 dazu true evtl kommt 15 dazu false evtl kommt 30 dazu false user> @lotto-tipp [40 25 7 35 21 16] ;;;; ;;;; Snippet #5 (def ref1 (ref 1)) (def ref2 (ref 1)) (defn lesethread [] (println "Thread 1: lese") (dotimes [i 6] (Thread/sleep 100) (dosync (println "T1, ref1: " @ref1 " ref2: " @ref2)))) (defn schreibthread [] (println "Thread 2: schreibe") (dosync (alter ref1 inc) (Thread/sleep 300) (alter ref2 inc))) user> (do (.start (Thread. lesethread)) (.start (Thread. schreibthread))) Thread 1: lese Thread 2: schreibe T1, ref1: 1 ref2: 1 T1, ref1: 1 ref2: 1 T1, ref1: 1 ref2: 1 T1, ref1: 2 ref2: 2 T1, ref1: 2 ref2: 2 T1, ref1: 2 ref2: 2 ;;;; ;;;; Snippet #6 (def ref1 (ref "Original 1")) (def ref2 (ref "Original 2")) user> [@ref1 @ref2] ["Original 1" "Original 2"] ;;;; ;;;; Snippet #7 (defn leserich "Liest die aktuellen Werte" [] (dotimes [i 10] (dosync (println "LESERICH" @ref1 @ref2) (flush)) (Thread/sleep 20))) (defn namenator "Liefert einen Namen. Mit unklugem Nebeneffekt" [num nam] (let [result (str "NEU" num ": " nam)] (println "NAMENATOR" result) result)) (defn schreiberling "Schreibt NAM in ref1 und ref2" [nam] (dosync (alter ref1 (fn [_] (namenator 1 nam))) (Thread/sleep 88) (alter ref2 (fn [_] (namenator 2 nam))))) ;;;; ;;;; Snippet #8 user> (do (.start (Thread. leserich)) (dotimes [i 3] (.start (Thread. (fn [] (schreiberling (+ i 10)))))) (Thread/sleep 2000)) LESERICH Original 1 Original 2 NAMENATOR NEU1: 10 NAMENATOR NEU1: 11 NAMENATOR NEU1: 12 LESERICH Original 1 Original 2 LESERICH Original 1 Original 2 NAMENATOR NEU2: 10 NAMENATOR NEU1: 11 NAMENATOR NEU1: 12 LESERICH NEU1: 10 NEU2: 10 LESERICH NEU1: 10 NEU2: 10 LESERICH NEU1: 10 NEU2: 10 NAMENATOR NEU2: 11 NAMENATOR NEU1: 12 LESERICH NEU1: 11 NEU2: 11 LESERICH NEU1: 11 NEU2: 11 NAMENATOR NEU2: 12 LESERICH NEU1: 12 NEU2: 12 LESERICH NEU1: 12 NEU2: 12 nil ;;;; ;;;; Snippet #9 (def rohling (ref "leer")) (defn lese-rohling [] (dosync (let [v @rohling] (println "lesen1" v) (Thread/sleep 2000) (println "lesen2" @rohling v)))) (defn brennen [] (dosync (println "brennen" @rohling) (Thread/sleep 600) (alter rohling (constantly "gebrannt")))) user> (do (.start (Thread. lese-rohling)) (.start (Thread. brennen))) lesen1 leer brennen leer lesen1 gebrannt lesen2 gebrannt gebrannt ;;;; ;;;; Snippet #10 (def rohling (ref "leer")) (defn ensure-rohling [] (dosync (let [v (ensure rohling)] (println "ensure1" v) (Thread/sleep 2000) (println "ensure2" @rohling v)))) user> (do (.start (Thread. ensure-rohling)) (.start (Thread. brennen))) ensure1 leer brennen leer brennen leer brennen leer ensure2 leer leer user> @rohling "gebrannt" ;;;; ;;;; Snippet #11 user> (def agts (agent ["James Bond"])) #'user/agts user> (type agts) clojure.lang.Agent user> @agts "James Bond" ;;;; ;;;; Snippet #12 (def agts (agent ["James Bond"])) (defn gehaltsliste-ueberwachen [] (dotimes [i 10] (println i "#Agenten:" (count @agts)) (Thread/sleep 2))) (defn agenten-einstellen [] (let [agenten ["Jerry Cotton" "Phil Decker" "John Steed" "Emma Peel" "Austin Powers"]] (doseq [a agenten] (send agts conj a) (println "Gesendet" a "->" @agts) (Thread/sleep 2)))) (defn geheimbund-aufbauen [] (.start (Thread. gehaltsliste-ueberwachen)) (.start (Thread. agenten-einstellen))) user> (geheimbund-aufbauen) 0 #Agenten: 1 Gesendet Jerry Cotton -> [James Bond] 1 #Agenten: 2 Gesendet Phil Decker -> [James Bond Jerry Cotton] 2 #Agenten: 3 Gesendet John Steed -> [James Bond Jerry Cotton Phil Decker] 3 #Agenten: 4 Gesendet Emma Peel -> [James Bond Jerry Cotton Phil Decker John Steed] 4 #Agenten: 5 Gesendet Austin Powers -> [James Bond Jerry Cotton Phil Decker John Steed Emma Peel] 5 #Agenten: 6 6 #Agenten: 6 7 #Agenten: 6 8 #Agenten: 6 9 #Agenten: 6 10 #Agenten: 6 ;;;; ;;;; Snippet #13 user> (def *t-1000* (agent {:count 0})) #'user/*t-1000* user> @*t-1000* {:count 0} (defn zeige-thread-action [state] (println "In Thread" (.getName (Thread/currentThread))) (if (< (:count state) 5) (do (send *t-1000* zeige-thread-action) (assoc state :count (inc (:count state)))) state)) user> (send *t-1000* zeige-thread-action) In Thread pool-1-thread-1 # user> In Thread pool-1-thread-2 In Thread pool-1-thread-3 In Thread pool-1-thread-4 In Thread pool-1-thread-4 In Thread pool-1-thread-4 ;;;; ;;;; Snippet #14 (def doppel-agent (agent "Villariba")) (defn ueberlaufen [aktuell neu] (if (and (= aktuell "Villariba") (= neu "Villabajo")) (throw (Exception. "Aufgedeckt!")) neu)) user> (error-mode doppel-agent) :fail user> (send doppel-agent ueberlaufen "Villabajo") # user> @doppel-agent "Villariba" user> (send doppel-agent ueberlaufen "Villabajo") java.lang.RuntimeException: Agent is failed, needs restart ;;;; ;;;; Snippet #15 user> (restart-agent doppel-agent "Villariba") "Villariba" user> (send doppel-agent ueberlaufen "Portunesien") # user> @doppel-agent "Portunesien" user> ;;;; ;;;; Snippet #16 (defn handler-fktn [a e] (println "Agent, State:" @a) (println "Fehler: " e) "Handler fertig") (defn werfer [& args] (println "Werfer, args" args) (throw (Exception. "Meine Exception"))) (def a (agent "A" :error-handler handler-fktn :error-mode :continue)) ; auch default user> (send a werfer) # Werfer, args (A) Agent, State: A Fehler: # user> @a "A" ;;;; ;;;; Snippet #17 user> (use '[clojure.java.io :only (reader)]) nil (def *ip-zaehler-agent* (agent {})) (defn inc-map-zaehler [a-map a-key] (let [cur-count (get a-map a-key 0)] (assoc a-map a-key (inc cur-count)))) (defn tokenize-zeile [zeile] ;; vereinfacht: nur remote ip {:remote-ip (subs zeile 0 (.indexOf zeile " "))}) (defn parse-apache-log [filename] (with-open [rdr (reader filename)] (doseq [l (line-seq rdr)] (let [e (tokenize-zeile l)] (send *ip-zaehler-agent* inc-map-zaehler (e :remote-ip)))))) user> (parse-apache-log "access.log") nil user> @*ip-zaehler-agent* {"93.158.148.x" 1, "65.55.207.x" 2, "74.222.4.x" 2, "65.55.106.x" 1, "92.76.249.x" 3, "202.78.240.x" 1} ;;;; ;;;; Snippet #18 user> (def cl-zahl (atom 0 :validator integer?)) #'user/cl-zahl user> (reset! cl-zahl "Cl") java.lang.IllegalStateException: Invalid reference state user> (reset! cl-zahl 17) 17 ;;;; ;;;; Snippet #19 user> (def ordnungszahl (atom 1 :validator #(< 0 % 119))) #'user/ordnungszahl user> (defn traum-in-dubna [] "Ununonium!" (reset! ordnungszahl 119)) #'user/traum-in-dubna user> (traum-in-dubna) java.lang.IllegalStateException: Invalid reference state ;;;; ;;;; Snippet #20 user> (get-validator ordnungszahl) # user> (def frei (atom ["Akzeptiert" "alles"])) #'user/frei user> (get-validator frei) nil user> (set-validator! ordnungszahl #(< 0 % 120)) nil user> (traum-in-dubna) 119 user> @ordnungszahl 119 ;;;; ;;;; Snippet #21 (defn mein-watcher [k f old new] (println "Watcher" [k f old new])) (def die-ref (ref "Anfang")) user> (add-watch die-ref :schluessel mein-watcher) # user> (dosync (ref-set die-ref "Ende")) Watcher [:schluessel # Anfang Ende] "Ende" ;;;; ;;;; Snippet #22 (defn th-info [] (let [t (Thread/currentThread)] {:Name (.getName t) :ID (.getId t) :Prio (.getPriority t) })) (defn print-th-info [] (println (interpose "\n" (th-info)))) ;;;; ;;;; Snippet #23 user> (.start (Thread. print-th-info)) ([:Name Thread-3] [:ID 15] [:Prio 5]) nil user> (.start (Thread. print-th-info)) ([:Name Thread-4] [:ID 16] [:Prio 5]) nil ;;;; ;;;; Snippet #24 user> (doto (Thread. print-th-info) (.setName "Ich, Thread") (.start)) # ([:Name Ich, Thread] [:ID 17] [:Prio 5]) user> ;;;; ;;;; Snippet #25 user> (import '(java.util.concurrent Executors)) java.util.concurrent.Executors (def mein-tpool (Executors/newFixedThreadPool 3)) user> (.getPoolSize mein-tpool) 0 user> (.getMaximumPoolSize mein-tpool) 3 user> (.execute mein-tpool print-th-info) nil ([:Name pool-3-thread-1] [:ID 18] [:Prio 5]) user> (.getPoolSize mein-tpool) 1 user> (def dummies (repeat 5 print-th-info)) #'user/dummies user> (.invokeAll mein-tpool dummies) ([:Name pool-3-thread-1] [:ID 18] [:Prio 5]) ([:Name pool-3-thread-1] [:ID 18] [:Prio 5]) ([:Name pool-3-thread-1] [:ID 18] [:Prio 5]) ([:Name pool-3-thread-2] [:ID 19] [:Prio 5]) ([:Name pool-3-thread-3] [:ID 20] [:Prio 5]) # user> (.getPoolSize mein-tpool) 3 ;;;; ;;;; Snippet #26 (defn langsamer-wert [] (Thread/sleep 5000) (System/currentTimeMillis)) (defn test-fut [] (println "Start" (System/currentTimeMillis)) (let [spaeter (future (langsamer-wert))] (println "Davor" (System/currentTimeMillis)) (println "Deref" (deref spaeter)) (println "Danach" (System/currentTimeMillis)))) user> (test-fut) Start 1268083317644 Davor 1268083317645 Deref 1268083322645 Danach 1268083322646 nil ;;;; ;;;; Snippet #27 user> (def kommt-gleich (future (langsamer-wert))) #'user/kommt-gleich user> (future-done? kommt-gleich) false user> (future-done? kommt-gleich) false user> (future-done? kommt-gleich) true user> (future? kommt-gleich) true ;;;; ;;;; Snippet #28 (defn fill-vec [k] (loop [i 0 v (transient [])] (if (< i k) (recur (inc i) (conj! v i)) (persistent! v)))) (def fv (fill-vec 100)) user> (type fv) clojure.lang.PersistentVector user> (take 10 fv) (0 1 2 3 4 5 6 7 8 9) ;;;; ;;;; Snippet #29 (defn fill-map [k] (loop [i 0 m (transient {})] (if (< i k) (recur (inc i) (assoc! m i (* i i))) (persistent! m)))) (def tm (fill-map 100)) user> (type tm) clojure.lang.PersistentHashMap user> (take 5 tm) ([0 0] [32 1024] [64 4096] [96 9216] [1 1]) ;;;; ;;;; Snippet #30 (defn fill-vec-persist [k] (loop [i 0 v []] (if (< i k) (recur (inc i) (conj v i)) v))) user> (time (dorun (fill-vec-persist 1000000))) "Elapsed time: 1020.711 msecs" user> (time (dorun (fill-vec 1000000))) "Elapsed time: 562.366 msecs" nil ;;;; ;;;; Snippet #31 (def r1 (ref 1)) (defn alt-und-alt [] (dosync (alter r1 inc) (alter r1 inc))) user> (alt-und-alt) 3 user> @r1 3 (def r2 (ref 2)) (defn comm-und-alt [] (dosync (commute r2 inc) (alter r2 inc))) user> (comm-und-alt) java.lang.IllegalStateException: Can't set after commute ;;;; ;;;; Snippet #32 ; STM history stress-test (defn stress [hmin hmax] (let [r (ref 0 :min-history hmin :max-history hmax) slow-tries (atom 0)] (future ;; langsame Transaktion (dosync (swap! slow-tries inc) (Thread/sleep 200) @r) (println "a is:" @r "history:" (.getHistoryCount r) "after:" @slow-tries "tries")) (dotimes [i 500] (Thread/sleep 10) (dosync (alter r inc))) ;; schnelle.... :done)) ;; Default Werte fuer Refs user> (stress 0 10) :done a is: 500 history: 10 after: 26 tries ;; Dieses Ergebnis weist darauf hin, dass die langsame ;; Transaktion nicht erfolgreich durchgeführt werden konnte, ;; bevor die dotimes-Schleife komplett durchlaufen wurde ;; (und :done zurückgab). user> (stress 0 30) a is: 414 history: 20 after: 21 tries :done ;; Hier wurde die langsame Transaktion erfolgreich beendet, ;; nachdem die Historie auf 20 angewachsen war. ;; Erfolg! Allerdings wurden 21 Versuche benötigt, um die ;; Historie von 0 wachsen zu lassen. Wir können helfen, ;; indem wir gleich mit größerer minimaler Historie starten: user> (stress 15 30) a is: 118 history: 20 after: 6 tries :done ;; Dieses Mal nur 6 Versuche, ausreichend, um die Historie ;; von 15 auf 20 anwachsen zu lassen. ;;;; ;;;; Snippet #33 (ns de.clojure-buch.genalg) (def population (atom {})) ;;;; ;;;; Snippet #34 (def das-ziel "Thursday Next") ;;;; ;;;; Snippet #35 (defn fitness-bewerten [indiv] ;; count ist schneller als String.length (+ (* 2 (Math/abs (- (count das-ziel) (count indiv)))) (reduce + (map #(if (= %1 %2) 0 1) indiv das-ziel)))) ;;;; ;;;; Snippet #36 (def gen-max-laenge 20) (def die-symbole (str "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ ")) (defn zufaelliges-symbol [] (nth die-symbole (rand-int (count die-symbole)))) (defn zufaelliges-gen [laenge] (apply str (take (inc (rand-int laenge)) (repeatedly zufaelliges-symbol)))) ;;;; ;;;; Snippet #37 (defn gen-auswahl [g1 g2] (if (= 0 (rand-int 10)) ;; Mutation (zufaelliges-symbol) (if (= 0 (rand-int 2)) g1 g2))) (defn laengen-auswahl [i1 i2] (let [ci1 (count i1) ci2 (count i2)] ;; 50% eine der beiden Laengen (if (= 0 (rand-int 2)) (if (= 0 (rand-int 2)) ci1 ci2) ;; 50% eine zufaellige Laenge dazwischen (max gen-max-laenge (+ (min ci1 ci2) (rand-int (Math/abs (- ci1 ci2)))))))) (defn gen-rekombination [i1 i2] (apply str (take (laengen-auswahl i1 i2) (map gen-auswahl (cycle i1) (cycle i2))))) ;;;; ;;;; Snippet #38 (def pop-groesse 1000) (defn zufaellige-population [groesse indiv-laenge] (into {} (map (fn [x] {x (fitness-bewerten x)}) (take groesse (repeatedly #(zufaelliges-gen indiv-laenge)))))) (defn irgendein-indiv [population] (let [ks (keys population)] (rand-nth ks))) (defn selektiere-indiv [pop selektions-druck vorzug] (let [cmp-fun (if (= vorzug :gut) < >)] (first (sort #(cmp-fun (pop %1) (pop %2)) (take selektions-druck (repeatedly #(irgendein-indiv pop))))))) ;;;; ;;;; Snippet #39 (def ^{:doc "Agent, der das System weiterlaufen laesst"} start-stop-agent (agent "stop")) (def ^{:doc "Wohnungen werden an der REPL eingerichtet. In jeder Wohnung lebt ein Agent, der neue Individuen erzeugt."} wohnungen) (def ^{:doc "Die Anzahl der Wohnungen muss auf den Sensenmann abgestimmt sein, damit die Population nicht waechst."} anzahl-wohnungen 3) (defn richte-wohnungen-ein [] (doall (for [i (range anzahl-wohnungen)] ;; jeder Agent zaehlt die erzeugten Individuen; (agent 0)))) (defn a-day-in-the-life "Zentrale Funktion fuer das Fortschreiten der Evolution." [] (let [o1 (selektiere-indiv @population 3 :gut) o2 (selektiere-indiv @population 3 :gut) new (gen-rekombination o1 o2) fit (fitness-bewerten new)] (swap! population conj {new fit}))) (defn a-day-in-the-life-agent-fn [status] ;; Sende uns selbst wieder an den Agent (when (= @start-stop-agent "running") (send *agent* a-day-in-the-life-agent-fn)) (a-day-in-the-life) (inc status)) ;;;; ;;;; Snippet #40 (def sensenmann (agent 0)) (defn hauch-des-todes [] (when (> (count @population) pop-groesse) (let [gen (selektiere-indiv @population 2 :schlecht)] (swap! population dissoc gen)))) (defn hauch-des-todes-agt-fun [status] (when (= @start-stop-agent "running") (send-off *agent* hauch-des-todes-agt-fun)) (hauch-des-todes) (inc status)) ;;;; ;;;; Snippet #41 (defn fuelle-start-population [] (reset! population (zufaellige-population pop-groesse gen-max-laenge))) (defn bereite-evolution-vor [] (fuelle-start-population) (send sensenmann (constantly 0)) (def wohnungen (richte-wohnungen-ein))) (defn starte-evolution [] (send start-stop-agent (constantly "running")) (await start-stop-agent) (send sensenmann hauch-des-todes-agt-fun) (map #(send % a-day-in-the-life-agent-fn) wohnungen)) (defn stop-evolution [] (send start-stop-agent (constantly "stopped"))) (defn beste-individuen ([anz] (let [p @population] (take anz (sort #(< (p (first %1)) (p (first %2))) p)))) ([] (beste-individuen 1))) (defn verfolge-evolution [] (while (= @start-stop-agent "running") (let [beste (beste-individuen 2) anzahl (count @population)] (printf "Population: %d" anzahl) (println " - Wohnungen: " (map deref wohnungen)) (println beste) (when (= 0 (second (first beste))) (stop-evolution)) (Thread/sleep 2000)))) ;;;;