Reaktive Programmierung Vorlesung 1 vom 02.04.19 Was ist Reaktive Programmierung?
Christoph Lüth, Martin Ring
Universität Bremen Sommersemester 2019
17:06:02 2019-07-10 1 [40]
Organisatorisches
IVorlesung: Mittwochs 14-16, MZH 1110
IÜbung: Donnerstags 16-18, MZH 1450 (nach Bedarf)
IWebseite:www.informatik.uni-bremen.de/~cxl/lehre/rp.ss19 IScheinkriterien:
IVoraussichtlich 6 Übungsblätter
IAlle bearbeitet, insgesamt 40% (Notenspiegel PI3)
IÜbungsgruppen 2 – 4 Mitglieder
IDanach: FachgesprächoderModulprüfung
RP SS 2019 2 [40]
Warum Reaktive Programmierung?
Herkömmliche Sprachen:
IPHP, JavaScript, Ruby, Python IC, C++, Java
I(Haskell) Eigenschaften:
IImperativundprozedural ISequentiell
Zugrundeliegendes Paradigma:
. . . aber die Welt ändert sich:
IDasNetzverbindet Rechner ISelbst eingebettete Systeme sind
vernetzt (Auto: ca. 130 Proz.) IMikroprozessoren sind
mehrkernig
ISysteme sindeingebettet, nebenläufig,reagierenauf ihre Umwelt.
RP SS 2019 3 [40]
Probleme mit dem herkömmlichen Ansatz
Programm
Daten Eingabe
Ausgabe
Daten Programm
Eingabe Ausgabe
Daten Programm
Eingabe Ausgabe
Eingabe
AusgabeProgramm Daten
Eingabe Ausgabe
Eingabe Ausgabe
Eingabe
Ausgabe
Daten Programm
Eingabe Ausgabe
Eingabe Ausgabe
Eingabe
Ausgabe Eingabe Ausgabe
Daten Programm
Eingabe Ausgabe
Eingabe Ausgabe
Eingabe Ausgabe
Eingabe
Ausgabe Eingabe Ausgabe
IProblem:Nebenläufigkeit
INebenläufigkeit verursacht Synchronisationsprobleme
IBehandlung:
ICallbacks (JavaScript, PHP)
IEvents (Java)
IGlobal Locks (Python, Ruby)
IProgrammiersprachenkonstrukte:
Locks, Semaphoren, Monitore
RP SS 2019 4 [40]
Amdahl’s Law
“The speedup of a program using multiple processors in parallel computing is limited by the sequential fraction of the program. For example, if 95% of the program can be parallelized, the theoretical maximum speedup using parallel computing would be 20×as shown in the diagram, no matter how many processors are used.”
20.00 18.00 16.00 14.00 12.00 10.00 8.00 6.00 4.00 2.00 0.00
Speedup 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
NumberLofLProcessors Amdahl’sLLaw
ParallelLPortion 50%
75%
90%
95%
Quelle: Wikipedia
RP SS 2019 5 [40]
The Reactive Manifesto
Ihttp://www.reactivemanifesto.org/
Responsive
Resilient
Message Driven Elastic
RP SS 2019 6 [40]
Was ist Reaktive Programmierung?
IImperativeProgrammierung: Zustandsübergang IProzeduralundOO: Verkapselter Zustand
IFunktionaleProgrammierung: Abbildung (mathematische Funktion) IReaktiveProgrammierung:
1 Datenabhängigkeit
2 Reaktiv=funktional+nebenläufig
RP SS 2019 7 [40]
Datenflusssprachen (data flow languages)
IFrühe Sprachen: VAL, SISAL, ID, LUCID (1980/1990) IHeutige Sprachen: Esterel, Lustre (Gérard Berry, Verimag)
IKeineZuweisungen, sondernDatenfluss ISynchron:alle Aktionen ohne Zeitverzug IVerwendung in der Luftfahrtindustrie (Airbus)
RP SS 2019 8 [40]
Struktur der VL
IKernkonzeptein Scala und Haskell:
INebenläufigkeit: Futures, Aktoren, Reaktive Ströme
IFFP: Bidirektionale und Meta-Programmierung, FRP, sexy types
IRobustheit: Eventual Consistency, Entwurfsmuster
IBilingualerÜbungsbetriebundVorlesung IKeinScala-Programmierkurs
IErlernen von Scala ist nützlicherSeiteneffekt
RP SS 2019 9 [40]
Fahrplan
IEinführung
IMonaden und Monadentransformer INebenläufigkeit: Futures and Promises IAktoren I: Grundlagen
IAktoren II: Implementation IMeta-Programmierung IBidirektionale Programmierung IReaktive Ströme I
IReaktive Ströme II
IFunktional-Reaktive Programmierung ISoftware Transactional Memory IEventual Consistency IRobustheit und Entwurfsmuster ITheorie der Nebenläufigkeit, Abschluss
RP SS 2019 10 [40]
Rückblick Haskell
RP SS 2019 11 [40]
Rückblick Haskell
IDefinition von Funktionen:
Ilokale Definitionen mitletundwhere IFallunterscheidung und guarded equations IAbseitsregel
IFunktionen höherer Ordnung
ITypen:
IBasisdatentypen:Int,Integer,Rational,Double,Char,Bool IStrukturierte Datentypen:[α],(α,β)
IAlgebraische Datentypen:dataMaybeα= Justα | Nothing
RP SS 2019 12 [40]
Rückblick Haskell
INichtstriktheit und verzögerte Auswertung IStrukturierung:
IAbstrakte Datentypen
IModule
ITypklassen
RP SS 2019 13 [40]
Ein- und Ausgabe in Haskell
Umwelt Haskell
Aktionen
Umwelt Reine
Funktionen
Haskell
Problem:
IFunktionen mit Seiteneffekten nicht referentiell transparent.
I readString :: . . .→String??
Lösung:
ISeiteneffekte am Typ erkennbar IAktionenkönnennurmit
Aktionenkomponiert werden I„einmal Aktion, immer Aktion“
RP SS 2019 14 [40]
Aktionen als abstrakter Datentyp
IADT mit OperationenKompositionundLifting
ISignatur:
typeIOα
(=) :: IOα→ (α→IOβ) →IOβ
return :: α→ IOα
IPluselementareOperationen (lesen, schreiben etc)
RP SS 2019 15 [40]
Elementare Aktionen
IZeile vonstdinlesen:
getLine :: IO String
IZeichenkette aufstdoutausgeben:
putStr :: String→ IO ()
IZeichenkette mit Zeilenvorschubausgeben:
putStrLn :: String→ IO ()
RP SS 2019 16 [40]
Die do-Notation
ISyntaktischer Zucker fürIO:
echo = getLine
=λs→ putStrLn s echo
⇐⇒
echo =do s← getLine putStrLn s echo
IRechts sind=,implizit.
IEs gilt dieAbseitsregel.
IEinrückungderersten Anweisungnachdobestimmt Abseits.
RP SS 2019 17 [40]
Zustandsabhängige Berechnungen
RP SS 2019 18 [40]
Funktionen mit Zustand
IIdee: Seiteneffektexplizitmachen
IFunktionf :A→Bmit Seiteneffekt inZustandS:
f :A×S→B×S
∼= f :A→S→B×S
IDatentyp:S→B×S
IKomposition: Funktionskomposition unduncurry curry :: ((α, β) →γ)→α→β→γ uncurry :: (α→β→γ)→ (α,β) →γ
RP SS 2019 19 [40]
In Haskell: Zustände explizit
IZustandstransformer:Berechnung mit Seiteneffekt in Typσ (polymorph überα)
type Stateσ α=σ→ (α, σ) IKomposition zweier solcher Berechnungen:
comp :: State σ α→ (α→ State σ β)→ State σ β comp f g = uncurry g◦f
ITrivialer Zustand:
l i f t :: α→ State σ α l i f t = curry id ILifting von Funktionen:
map :: (α→β)→ State σ α→ State σ β map f g = (λ(a , s )→ ( f a , s ) )◦g
RP SS 2019 20 [40]
Zugriff auf den Zustand
IZustand lesen:
get :: (σ→α)→ State σ α get f s = ( f s , s )
IZustand setzen:
set :: (σ→σ)→ State σ () set g s = (() , g s )
RP SS 2019 21 [40]
Einfaches Beispiel
IZähler als Zustand:
typeWithCounterα= State Int α
IBeispiel: Funktion, die in Kleinbuchstaben konvertiert undzählt cntToL :: String→ WithCounter String
cntToL [ ] = l i f t ""
cntToL (x : xs )
| isUpper x = cntToL xs ‘comp‘
λys→ set (+1) ‘comp‘
λ()→ l i f t (toLower x : ys )
| otherwise = cntToL xs ‘comp‘ λys→ l i f t (x : ys ) IHauptfunktion (verkapseltState):
cntToLower :: String→ ( String , Int ) cntToLower s = cntToL s 0
RP SS 2019 22 [40]
Monaden
RP SS 2019 23 [40]
Monaden als Berechnungsmuster
IIncntToLwerden zustandsabhängige Berechnungen verkettet.
ISo ähnlich wie bei Aktionen!
State:
type Stateσ α
comp :: Stateσ α→ (α→ State σ β)→
Stateσ β
l i f t :: α→ Stateσ α
map :: (α→β)→ Stateσ α→
Stateσ β
Aktionen:
typeIOα
(=) :: IOα→ (α→IOβ) → IOβ
return :: α→IOα
fmap :: (α→β)→IOα→
IOβ Berechnungsmuster:Monade
RP SS 2019 24 [40]
Monaden als Berechngsmuster
Eine Monade ist:
Imathematisch: durch Operationen und Gleichungen definiert (verallgemeinerte algebraische Theorie)
Ials Berechnungsmuster:verknüpfbareBerechnungen mit einem Ergebnis
IinHaskell: durch mehrere Typklassen definierte Operationen mit Eigenschaften
RP SS 2019 25 [40]
Monaden in Haskell
IAktion auf Funktionen:
class Functor f where
fmap :: (a →b) → f a → f b fmapbewahrt Identität und Komposition:
fmap id == id
fmap ( f◦g) == fmap f◦fmap g
IDie Eigenschaftensolltengelten, können aber nicht überprüft werden.
IStandard: “Instances of Functor should satisfy the following laws.”
RP SS 2019 26 [40]
Monaden in Haskell
IApplicative:
class Functor f=>Applicative f where pure :: a→ f a
<∗>:: f (a →b) → f a → f b
Eigenschaften: links-neutralität, bewahrt Komposition, Homomorphismus:
pure id<∗>v == v
pure (◦)<∗>u<∗>v<∗>w == u<∗>(v<∗>w) pure f<∗>pure x == pure ( f x)
u<∗>pure y == pure ($ y)<∗>u
RP SS 2019 27 [40]
Monaden in Haskell
IVerkettung (=) und Lifting (return):
class Applicative m=>Monad mwhere (=) :: m a → (a →m b) →m b return :: a →m a
=ist assoziativ undreturndas neutrale Element:
return a= k == k a m= return == m
m= (λx →k x= h) == (m= k)= h
IAuch diese Eigenschaften können nicht geprüft werden.
IDen syntaktischen Zucker (do-Notation) gibt’s umsonst dazu.
RP SS 2019 28 [40]
Monaden mit Möglichkeiten
IAlternativen:
class Applicative f =>Alternative f where empty :: f a
<|> :: f a→ f a→ f a
IMonaden mit Alternative (e.g. List):
class ( Alternative m, Monad m) =>MonadPlus mwhere mzero :: m a
mzero = empty
mplus :: m a→m a →m a mplus = (<|>)
IGleichungen:mzeroIdentität fürmplusund=,mplusassoziativ.
RP SS 2019 29 [40]
Beispiele für Monaden
IZustandstransformer:Reader,Writer,State
IFehler und Ausnahmen:Maybe,Either
IMehrdeutige Berechnungen:L i s t,Set
RP SS 2019 30 [40]
Die Reader-Monade
IAus dem Zustand wird nur gelesen:
data Readerσ α= R {run :: σ→α}
IInstanzen:
instance Functor (Readerσ) where fmap f (R g) = R ( f . g)
instance Monad (Readerσ) where return a = R ( const a)
R f= g = R $λs→ run (g ( f s ) ) s INur eine elementare Operation:
get :: (σ→α)→Reader σ α get f = R $λs→ f s
RP SS 2019 31 [40]
Fehler und Ausnahmen
IMaybeals Monade:
instance Functor Maybewhere fmap f ( Just a) = Just ( f a) fmap f Nothing = Nothing
instanceMonad Maybewhere Just a= g = g a Nothing= g = Nothing return = Just IÄhnlich mitEither
IBerechnungsmodell:Ausnahmen(Fehler)
I f :: α→Maybeβist Berechnung mit möglichem Fehler IFehlerfreie Berechnungen werden verkettet
IFehler (NothingoderLeft x) werden propagiert
RP SS 2019 32 [40]
Mehrdeutigkeit
I L i s tals Monade:
IKönnen wir so nicht hinschreiben, Syntax vordefiniert
instance Functor [α] where fmap = map
instance Monad [α] where a : as= g = g a ++ ( as= g)
[ ]= g = [ ] return a = [ a ]
IBerechnungsmodell: Mehrdeutigkeit
I f :: α→ [β]ist Berechnung mitmehrerenmöglichen Ergebnissen IVerkettung: Anwendung der folgenden Funktion aufjedesErgebnis
(concatMap)
RP SS 2019 33 [40]
Beispiel
IBerechnung aller Permutationen einer Liste:
1 Ein Element überall in eine Liste einfügen:
i n s :: α→ [α]→ [ [α] ] i n s x [ ] = return [ x ] i n s x (y : ys ) = [ x : y : ys ] ++do
i s ← i n s x ys return $ y : i s
2 Damit Permutationen (rekursiv):
perms :: [α]→ [ [α] ] perms [ ] = return [ ] perms (x : xs ) =do
ps← perms xs i s ← i n s x ps return i s
RP SS 2019 34 [40]
Der Listenmonade in der Listenkomprehension
IBerechnung aller Permutationen einer Liste:
1 Ein Element überall in eine Liste einfügen:
ins ’ :: α→ [α]→ [ [α] ] ins ’ x [ ] = [ [ x ] ]
ins ’ x (y : ys ) = [ x : y : ys ] ++ map (y : ) ( ins ’ x ys )
2 Damit Permutationen (rekursiv):
perms ’ :: [α]→ [ [α] ] perms ’ [ ] = [ [ ] ]
perms ’ (x : xs ) = [ i s | ps ←perms ’ xs , i s ← ins ’ x ps ]
IListenkomprehension∼= Listenmonade
RP SS 2019 35 [40]
IO ist keine Magie
RP SS 2019 36 [40]
Referenzen in Haskell
IZustand alsfinite mapvon Referenzen auf Werte IUngetypt:SimpleRefs
ITyp der Werte ist Typparameter des Zustands readRef :: Ref→ Stateful a a
writeRef :: Ref→ a→ Stateful a ()
IGetypt:Refs
ITyp der Werte durch Typparameter der Referenz INutztdynamische Typen:
readRef :: Typeable a=>Ref a→ Stateful a writeRef :: Typeable a=>Ref a→a→ Stateful ()
RP SS 2019 37 [40]
Implizite vs. explizite Zustände
IWie funktioniert jetztIO?
INachteil vonState: Zustand istexplizit
IKanndupliziertwerden
IDaher: Zustandimplizitmachen
IDatentypverkapseln(keinrun)
IZugriff aufStatenur über elementare Operationen
RP SS 2019 38 [40]
Aktionen als Zustandstransformationen
IIdee: Aktionen sindTransformationenauf SystemzustandS ISbeinhaltet
ISpeicher als AbbildungA*V(AdressenA, WerteV)
IZustand des Dateisystems
IZustand des Zufallsgenerators
IIn Haskell: TypRealWorld
I“Virtueller” Typ, Zugriff nur über elementare Operationen
IEntscheidend nurReihenfolgeder Aktionen
RP SS 2019 39 [40]
Zusammenfassung
IWar das jetztreaktiv?
IHaskell istfunktional
IFür eine reaktive Sprache fehltNebenläufigkeit
INächstes Mal:
IMonadenkomponieren— Monadentransformer
IDanach: Nebenläufigkeit in Haskell und Scala
RP SS 2019 40 [40]
Reaktive Programmierung Vorlesung 2 vom 10.04.2019 Monaden und Monadentransformer
Christoph Lüth, Martin Ring Universität Bremen Sommersemester 2019
17:06:03 2019-07-10 1 [21]
Fahrplan
IEinführung
IMonaden und Monadentransformer INebenläufigkeit: Futures and Promises IAktoren I: Grundlagen
IAktoren II: Implementation IMeta-Programmierung IBidirektionale Programmierung IReaktive Ströme I
IReaktive Ströme II
IFunktional-Reaktive Programmierung ISoftware Transactional Memory IEventual Consistency IRobustheit und Entwurfsmuster ITheorie der Nebenläufigkeit, Abschluss
RP SS 2019 2 [21]
Inhalt
IMonaden zusammensetzen
IMonadentransformer
IMonaden in Scala
RP SS 2019 3 [21]
Monaden
RP SS 2019 4 [21]
Beispiele für Monaden
IZustandstransformer:Reader,Writer,State
IFehler und Ausnahmen:Maybe,Either
IMehrdeutige Berechnungen:L i s t,Set
RP SS 2019 5 [21]
Fallbeispiel: Auswertung von Ausdrücken
RP SS 2019 6 [21]
Monaden im Einsatz
IAuswertung von Ausdrücken:
data Expr = Var String
|Num Double
| Plus Expr Expr
| Minus Expr Expr
| Times Expr Expr
| Div Expr Expr
IMögliche Arten von Effekten:
IPartialität (Division durch 0) IZustände (für die Variablen) IMehrdeutigkeit
IAuswertung ohne Effekte:
eval :: Expr→Double eval (Var _) = 0 eval (Num n) = n
eval ( Plus a b) = eval a+ eval b eval (Minus a b) = eval a−eval b eval (Times a b) = eval a∗ eval b eval (Div a b) = eval a/ eval b
RP SS 2019 7 [21]
Auswertung mit Fehlern
IPartialität durchMaybe-Monade eval :: Expr →Maybe Double eval (Var _) = return 0 eval (Num n) = return n
eval ( Plus a b) =dox← eval a ; y← eval b ; return $ x+ y eval (Minus a b) =dox← eval a ; y← eval b ; return $ x−y eval (Times a b) =dox← eval a ; y← eval b ; return $ x∗y eval (Div a b) =do
x←eval a ; y← eval b ; i f y == 0thenNothingelse Just $ x/y
RP SS 2019 8 [21]
Auswertung mit Zustand
IZustand durchReader-Monade importReaderMonad
import qualified Data .Map as M type State = M.Map String Double eval :: Expr→Reader State Double eval (Var i ) = get (M. ! i ) eval (Num n) = return n
eval ( Plus a b) =dox← eval a ; y← eval b ; return $ x+ y eval (Minus a b) =dox← eval a ; y← eval b ; return $ x−y eval (Times a b) =dox← eval a ; y← eval b ; return $ x∗ y eval (Div a b) =dox← eval a ; y← eval b ; return $ x/ y
RP SS 2019 9 [21]
Mehrdeutige Auswertung
IDazu: Erweiterung vonExpr:
dataExpr = Var String
|. . .
| Pick Expr Expr
eval :: Expr → [ Double ] eval (Var i ) = return 0 eval (Num n) = return n
eval ( Plus a b) =dox← eval a ; y← eval b ; return $ x+ y eval (Minus a b) =dox← eval a ; y← eval b ; return $ x−y eval (Times a b) =dox← eval a ; y← eval b ; return $ x∗y eval (Div a b) =dox← eval a ; y← eval b ; return $ x/y eval ( Pick a b) =dox← eval a ; y← eval b ; [ x , y ]
RP SS 2019 10 [21]
Kombination der Effekte
IBenötigtKombinationder Monaden.
IMonadeRes:
IZustandsabhängig IMehrdeutig IFehlerbehaftet
data Resσ α= Res { run :: σ→ [Maybeα] }
IAndere Kombinationen möglich:
data Resσ α= Res (σ→Maybe [α] ) data Resσ α= Res (σ→ [α] ) data Resσ α= Res ( [σ→α] )
RP SS 2019 11 [21]
Res: Monadeninstanz
IFunctordurch Komposition derfmap:
instance Functor (Resσ)where
fmap f (Res g) = Res $ fmap (fmap f ) . g
IMonadist Kombination instanceMonad (Resσ)where
return a = Res ( const [ Just a ] ) Res f= g = Res $λs→doma← f s
casemaof
Just a→run (g a) s Nothing→return Nothing
RP SS 2019 12 [21]
Res: Operationen
IZugriff auf den Zustand:
get :: (σ→α)→Resσ α get f = Res $λs→ [ Just $ f s ] IFehler:
f a i l :: Resσ α
f a i l = Res $ const [ Nothing ] IMehrdeutige Ergebnisse:
j o i n :: α→α→Resσ α
j o i n a b = Res $λs→ [ Just a , Just b ]
RP SS 2019 13 [21]
Auswertung mit Allem
IIm MonadenReskönnen alle Effekte benutzt werden:
typeState = M.Map String Double eval :: Expr →Res State Double eval (Var i ) = get (M. ! i ) eval (Num n) = return n
eval ( Plus a b) =dox←eval a ; y←eval b ; return $ x+ y eval (Minus a b) =dox←eval a ; y←eval b ; return $ x−y eval (Times a b) =dox←eval a ; y←eval b ; return $ x∗y eval (Div a b) =dox←eval a ; y←eval b
i f y == 0then f a i l else return $ x /y eval ( Pick a b) =dox←eval a ; y←eval b ; j o i n x y ISystematische Kombination durchMonadentransformer
IMonade mit Platzhalter für weitere Monaden
RP SS 2019 14 [21]
Kombination von Monaden
RP SS 2019 15 [21]
Das Problem
IMonaden sind nichtkompositional:
typemn a = m (n a)
instance (Monad m, Monad n)=>Monad mn
IWarum?
IWie wären=,returndefiniert?
IFunktorensindkompositional.
RP SS 2019 16 [21]
Die “Lösung”
IMonadentransformer
IMonaden mit einem “Loch” (i.e. parametrisierte Monaden)
RP SS 2019 17 [21]
Beispiel
IZustandsmonadentransformer:StateMonadT
dataStateT m s a = St { runSt :: s→m (a , s ) }
IAusnahmenmonadtransformer:ExnMonadT
dataExnT m e a = ExnT { runEx :: m ( Either e a) }
IKomposition:
typeResMonad a = StateT (ExnT I d e n t i t y Error ) State a
RP SS 2019 18 [21]
Probleme
I“Lifting” von Hand
IKomposition muss fallweise entschieden werden:
IException und Writer kann kanonisch mit allen kombiniert werden IState und List nicht mit allen, oder unterschiedlich
RP SS 2019 19 [21]
Monadtransformer in Haskell: mtl
IKlassendeklarationen erlauben Typinferenz für automatisches Lifting
IZustandsmonaden, Exceptions, Reader, Writer, Listen, IO
IFallbeispiel: Interpreter für eine imperative Sprache
RP SS 2019 20 [21]
Zusammenfassung
IMonaden sindMusterfürBerechnungenmitSeiteneffekten IBeispiele:
IZustandstransformer IFehler und Ausnahmen INichtdeterminismus
IKombination von Monaden:Monadentransformer IMonadentransformer: parametrisierte Monaden Imtl-Bücherei erleichtert Kombination IPrinzipielle Begrenzungen
IGrenze: Nebenläufigkeit−→Nächste Vorlesung
RP SS 2019 21 [21]
Reaktive Programmierung Vorlesung 3 vom 24.04.2019 Nebenläufigkeit: Futures and Promises
Christoph Lüth, Martin Ring Universität Bremen Sommersemester 2019
17:06:05 2019-07-10 1 [26]
Fahrplan
IEinführung
IMonaden und Monadentransformer INebenläufigkeit: Futures and Promises IAktoren I: Grundlagen
IAktoren II: Implementation IMeta-Programmierung IBidirektionale Programmierung IReaktive Ströme I
IReaktive Ströme II
IFunktional-Reaktive Programmierung ISoftware Transactional Memory IEventual Consistency IRobustheit und Entwurfsmuster ITheorie der Nebenläufigkeit, Abschluss
RP SS 2019 2 [26]
Inhalt
IKonzepte der Nebenläufigkeit
INebenläufigkeit in Scala und Haskell
IFutures and Promises
RP SS 2019 3 [26]
Konzepte der Nebenläufigkeit
RP SS 2019 4 [26]
Begrifflichkeiten
I Thread (lightweight process) vs. Prozess Programmiersprache/Betriebssystem Betriebssystem (z.B. Java, Haskell/Linux)
gemeinsamerSpeicher getrennterSpeicher
Erzeugungbillig Erzeugungteuer
mehrereproProgramm einerproProgramm
IMultitasking:
Ipräemptiv:Kontextwechsel wirderzwungen Ikooperativ:Kontextwechsel nurfreiwillig
RP SS 2019 5 [26]
Threads in Java
IErweiterung der KlassenThreadoderRunnable IGestartet wird Methoderun ()— durch eigene überladen IStarten des Threads durch Aufruf der Methodes t a r t () IKontextwechsel mity i e l d ()
IJe nach JVM kooperativoderpräemptiv.
ISynchronisation mitMonitoren(synchronize)
RP SS 2019 6 [26]
Threads in Scala
IScala nutzt das Threadmodell der JVM
IKein sprachspezifisches Threadmodell
IDaher sind Threads vergleichsweiseteuer.
ISynchronisation auf unterster Ebene durch Monitore (synchronized)
IBevorzugtes Abstraktionsmodell:Aktoren(dazu später mehr)
RP SS 2019 7 [26]
Threads in Haskell: Concurrent Haskell
ISequentiellesHaskell: Reduktion eines Ausdrucks IAuswertung
INebenläufigesHaskell: Reduktion eines Ausdrucks anmehreren Stellen
Ighcimplementiert Haskell-Threads
IZeitscheiben (Default 20ms), Kontextwechsel bei Heapallokation IThreaderzeugung und Kontextswitch sindbillig
IModulControl . Concurrententhält Basisfunktionen IWenige Basisprimitive, darauf aufbauend Abstraktionen ISynchronisation mit Futures
RP SS 2019 8 [26]
Futures
IFutures machen Nebenläufigkeitexplizit IGrundprinzip:
IAusführung eines Threads wirdverzögert IKonsument startet erst, wenn Ergebnis vorhanden.
put
Produzent Konsument
Note: Not a UML sequence diagram
Initiator
RP SS 2019 9 [26]
Futures in Scala
RP SS 2019 10 [26]
Futures in Scala
IAntwort alsCallback:
t r a i t Future[+T] {
def onComplete( f : Try [T] ⇒ Unit ) : Unit defmap[U] ( f : T⇒U) : Future [U]
def flatMap [U] ( f : T⇒ Future [U] ) : Future [U]
def f i l t e r (p : T⇒ Boolean) : Future [T]
}
Imap, flatMap , f i l t e rfür monadische Notation IFactory-Methode für einfache Erzeugung
IVordefiniert inscala . concurrent . Future, Beispielimplementation Future . scala
RP SS 2019 11 [26]
Beispiel: Robot . s c a l a
IRoboter, kann sich umnPositionen bewegen:
i f (n ≤ 0) this else i f ( battery > 0) {
Thread . sleep (100∗Random. nextInt (10) ) ; Robot( id , pos+1, battery−1) .mv(n−1) } else throw newLowBatteryException
defmove(n : Int ) : Future [ Robot ] = Future { mv(n) } override def toString = s"Robot#$id at $pos [ battery :
$battery ] "
RP SS 2019 12 [26]
Beispiel: Moving the robots
object Examples { def ex1 = {
val robotSwarm = L i s t . range (1 ,6) .map{ i⇒ Robot( i ,0 ,10)}
val moved = robotSwarm .map(_.move(10) ) moved.map(_. onComplete( p r i n t l n ) ) p r i n t l n ("Started moving . . . ")
I6 Roboter erzeugen, alle um zehn Positionen bewegen.
IWie lange dauert das?
I0 Sekunden (nach spät. 10 Sekunden Futures erfüllt) IWas wir verschweigen:ExecutionContext
RP SS 2019 13 [26]
Compositional Futures
IWir können Futures komponieren I“Spekulation auf die Zukunft”
IBeispiel: Roboterbewegung
def ex2 = { val r= Robot(99 , 0 , 20) ; for { r1← r .move(3)
r2← r1 .move(5) r3← r2 .move(2)
IFehler (Failure) werden propagiert
RP SS 2019 14 [26]
Promises
IPromises sind das Gegenstück zu Futures t r a i t Promise {
def complete( r e s u l t : Try [T] ) def success ( r e s u l t : T) def future : Future [T]
}
object Promise {
def apply [T] : Promise [T] = . . . }
IDas Future eines Promises wird durch diecompleteMethodeerfüllt.
RP SS 2019 15 [26]
Futures in Haskell
RP SS 2019 16 [26]
Concurrent Haskell: Wesentliche Typen und Funktionen
IJeder Thread hat einen Identifier: abstrakter TypThreadId INeuen Thread erzeugen:forkIO :: IO()→IO ThreadId IThread stoppen: killThread :: ThreadId→IO () IKontextwechsel: yield :: IO ()
IEigener Thread:myThreadId :: IO ThreadId IWarten:threadDelay :: Int →IO ()
RP SS 2019 17 [26]
Concurrent Haskell — erste Schritte
IEin einfaches Beispiel:
write :: Char→IO ()
write c =doputChar c ; write c main :: IO ()
main =doforkIO ( write ’X’ ) ; write ’O’
IAusgabeghc: (X∗|O∗)∗
RP SS 2019 18 [26]
Futures in Haskell: MVars
IBasissynchronisationmechanismusin Concurrent Haskell IAlles andereabgeleitet
IGrundprinzip:
take
put
Produzent Konsument
Note: Not a UML sequence diagram
RP SS 2019 19 [26]
Futures in Haskell: MVars
IMVarαistpolymorphüber dem Inhalt IEntwederleerodergefülltmit Wert vom Typα IVerhalten beim Lesen und Schreiben:
Zustand vorher: leer gefüllt
Lesen blockiert(bis gefüllt) danach leer Schreiben danach gefüllt blockiert(bis leer) INB.Aufweckenblockierter ProzesseeinzelninFIFO
RP SS 2019 20 [26]
Basisfunktionen MVars
INeue Variable erzeugen (leer oder gefüllt):
newEmptyMVar :: IO (MVarα) newMVar :: α→ IO (MVarα) ILesen:
takeMVar :: MVarα→ IOα ISchreiben:
putMVar :: MVarα→α→ IO ()
IEs gibt noch weitere (nicht-blockierend lesen/schreiben, Test ob gefüllt,mapetc.)
RP SS 2019 21 [26]
Ein einfaches Beispiel: Robots Revisited
dataRobot = Robot {id :: Int , pos :: Int , battery :: Int}
IHauptfunktion: MVar anlegen, nebenläufig Bewegung starten move :: Robot→ Int→IO (MVar Robot)
move r n =do
m←newEmptyMVar; forkIO (mv m r n) ; return m IBewegungsfunktion:
mv :: MVar Robot→Robot→ Int→ IO () mv v r n
| n≤0 = putMVar v r
| otherwise = do
m←randomRIO(0 ,10) ; threadDelay (m∗100000) mv v r{pos= pos r + 1 , battery= battery r−1} (n−1)
RP SS 2019 22 [26]
Abstraktion von Futures
IAusMVarαkonstruierte Abstraktionen
ISemaphoren (QSemausControl . Concurrent .QSem):
waitQSem :: QSem→ IO () signalQSem :: QSem→ IO () ISieheSem. hs
IDamit auchsynchronizedwie in Java (huzzah!) IKanäle (ChanαausControl . Concurrent .Chan):
writeChan :: Chanα→α→IO () readChan :: Chanα→IOα
RP SS 2019 23 [26]
Asynchrone Ausnahmen
IAusnahmen unterbrechen den sequentiellen Kontrollfluß IIn Verbindung mit Nebenläufigkeitüberraschende Effekte:
m←newEmptyMVar
forkIO (do{s←takeMVar m; putStrLn s }) threadDelay (100000)
putMVar m ( er ro r "FOO! ")
IIn welchem Thread wird die Ausnahme geworfen?
IWo kann sie gefangen werden?
IDeshalb haben in Scala die Future-Callbacks den Typ:
t r a i t Future[+T] { def onComplete( f : Try [T]⇒ Unit ) : Unit
RP SS 2019 24 [26]
Explizite Fehlerbehandlung mit Try
IDie Signatur einer Methode verrät nichts über mögliche Fehler:
i f (n ≤ 0) this else i f ( battery > 0) {
ITry [T]macht Fehler explizit (Materialisierungoder Reifikation):
sealed abstract class Try[+T] {
def flatMap [U] ( f : T⇒ Try [U] ) : Try [U] =this match{ case Success (x)⇒
try f (x) catch { case NonFatal(ex)⇒ Failure (ex) } case f a i l : Failure⇒ f a i l }
case class Success [T] ( x : T) extendsTry [T]
case class Failure (ex : Throwable) extends Try [ Nothing ] IIstTryeine Monade? Nein,Try(e) flatMap f 6= f e
RP SS 2019 25 [26]
Zusammenfassung
INebenläufigkeit in Scalabasiert auf der JVM:
IRelativ schwergewichtige Threads, Monitore (synchronized) INebenläufigkeit in Haskell: Concurrent Haskell
ILeichtgewichtige Threads,MVar
IFutures: Synchronisation über veränderlichen Zustand IIn Haskell alsMVarmit Aktion (IO)
IIn Scala alsFuturemit Callbacks
IExplizite Fehler bei Nebenläufigkeitunverzichtbar IMorgen: Scala Collections, nächste VL: das Aktorenmodell
RP SS 2019 26 [26]
Reaktive Programmierung Vorlesung 4 vom 25.04.19 The Scala Collection Library
Christoph Lüth, Martin Ring Universität Bremen Sommersemester 2019
17:06:06 2019-07-10 1 [26]
Heute: Scala Collections
ISindnichtin die Sprache eingebaut!
ITrotzdem komfortabel
val ages = Map("Homer"→ 36 , "Marge"→ 34) ages ("Homer") // 36
ISehr vielseitig (Immutable, Mutable, Linear, Random Access, Read Once, Lazy, Strict, Sorted, Unsorted, Bounded...)
IUnd sehr generisch
val a = Array (1 ,2 ,3) ++ L i s t (1 ,2 ,3) a . flatMap( i⇒ Seq( i , i +1, i +2))
RP SS 2019 2 [26]
Scala Collections Bücherei
Sehr einheitliche Schnittstellen aber komplexe Bücherei:
RP SS 2019 3 [26]
Scala Collections Bücherei - Immutable
RP SS 2019 4 [26]
Scala Collections Bücherei - Mutable
RP SS 2019 5 [26]
Konstruktoren und Extraktoren
IEinheitliche Konstruktoren:
Traversable (1 , 2 , 3) I t e r a b l e ("x", "y", "z")
Map("x"→ 24 , "y"→ 25 , "z"→ 26) Set ( Color . red , Color . green , Color . blue ) SortedSet (" h e l l o ", "world")
Buffer (x , y , z ) IndexedSeq (1.0 , 2.0) LinearSeq (a , b , c) . . .
IEinheitliche Extraktoren:
val Seq(a , b , c) = Seq(1 ,2 ,3) // a = 1; b = 2; c = 3 . . .
RP SS 2019 6 [26]
Exkurs: Funktionen in Scala
IScala ist rein Objektorientiert.
Ijeder Wert ist ein Objekt
Ijede Operation ist ein Methodenaufruf
IAlso ist eine Funktion ein Objekt
Iund ein Funktionsaufruf ein Methodenaufruf.
t r a i t Function1[−T1,+R] { def apply (v1 : T1) : R }
ISyntaktischer Zucker:f (5)wird zuf . apply(5)
RP SS 2019 7 [26]
Exkurs: Konstruktoren in Scala
IDer syntaktische Zucker für Funktionen erlaubt uns Konstruktoren ohnenewzu definieren:
t r a i t Person { def age : Int defname: String }
object Person {
def apply (a : Int , n : String ) =newPerson { def age = a
defname = n }
}
val homer = Person(36 ,"Homer") IVgl. Case Classes
RP SS 2019 8 [26]
Exkurs: Extraktoren in Scala
IDas Gegenstück zuapplyistunapply.
Iapply(Konstruktor): Argumente−→Objekt Iunapply(Extraktor): Objekt−→Argumente IWichtig für Pattern Matching (Vgl. Case Classes)
object Person {
def apply (a : Int , n : String ) = <...>
def unapply(p : Person) : Option [ ( Int , String ) ] = Some((p . age , p .name) )
}
homermatch{
case Person(age , name) i f age < 18⇒ s" h e l l o young
$name"
case Person(_, name)⇒ s" h e l l o old $name"
}
val Person(a , n) = homer
RP SS 2019 9 [26]
scala.collection.Traversable[+A]
ISuper-trait von allen anderen Collections.
IEinzige abstrakte Methode:
def foreach [U] ( f : Elem⇒ U) : Unit IViele wichtige Funktionen sind hier schon definiert:
I++[B](that: Traversable[B]): Traversable[B]
Imap[B](f: A => B): Traversable[B]
Ifilter(f: A => Boolean): Traversable[A]
IfoldLeft[B](z: B)(f: (B,A) => B): B
IflatMap[B](f: A => Traversable[B]): Traversable[B]
Itake, drop, exists, head, tail, foreach, size, sum, groupBy, takeWhile ...
IProblem: So funktionieren die Signaturen nicht!
IDie folgende Folie ist für Zuschauer unter 16 Jahren nicht geeignet...
RP SS 2019 10 [26]
Die wahre Signatur von map
defmap[B, That ] ( f : A⇒ B) (implicit bf : CanBuildFrom [ Traversable [A] , B, That ] ) : That
Was machen wir damit?
ISchnell wieder vergessen
IAber im Hinterkopf behalten: Die Signaturen in der Dokumentation sind “geschönt”!
RP SS 2019 11 [26]
Seq[+A], IndexedSeq[+A], LinearSeq[+A]
IHaben eine länge (length)
IElemente haben feste Positionen (indexOf, indexOfSlice, ...) IKönnen Sortiert werden (sorted, sortWith, sortBy, ...) IKönnen Umgedreht werden (reverse, reverseMap, ...) IKönnen mit anderen Sequenzen verglichen werden (startsWith,
...)
INützliche Subtypen:List,Stream,Vector,Stack,Queue, mutable.Buffer
IWelche ist die richtige für mich?
http://docs.scala-lang.org/overviews/collections/
performance-characteristics.html
RP SS 2019 12 [26]
Set[+A]
IEnthalten keine doppelten Elemente
IUnterstützen Vereinigungen, Differenzen, Schnittmengen:
Set ("apple"," strawberry ") ++ Set ("apple","peach")
> Set ("apple", " strawberry ", "peach")
Set ("apple"," strawberry ")−−Set ("apple","peach")
> Set (" strawberry ")
Set ("apple", " strawberry ") & Set ("apple", "peach")
> Set ("apple")
INützliche Subtypen:SortedSet,BitSet
RP SS 2019 13 [26]
Map[K,V]
IIst eine Menge von Schlüssel-Wert-Paaren:
Map[K,V] <: Iterable[(K,V)]
IIst eine partielle Funktion von Schlüssel zu Wert:
Map[K,V] <: PartialFunction[K,V]
IWerte können “nachgeschlagen” werden:
val ages = Map("Homer"→ 39 , "Marge"→ 34) ages ("Homer")
> 39
ages isDefinedAt "Bart" // ages contains "Bart"
>false ages get "Marge"
> Some(34)
INützliche Subtypen:mutable.Map
RP SS 2019 14 [26]
Array
I Arraysind “special”:
IKorrespondieren zu Javas Arrays IKönnen aber auchgenerischseinArray [T]
IUnd sind kompatibel zu Sequenzen
IProblem mit Generizität:
def evenElems [T] ( xs : Vector [T] ) : Array [T] = { val arr =newArray [T] ( ( xs . length + 1) / 2) for ( i← 0 u n t i l xs . length by 2)
arr ( i / 2) = xs ( i ) arr }
RP SS 2019 15 [26]
Array
IType erasurezur Laufzeit — daher:Class tagbenötigt
def evenElems [T] ( xs : Vector [T] ) (implicitm: ClassTag [T] ) : Array [T] = . . .
def evenElems [T: ClassTag ] ( xs : Vector [T] ) : Array [T] = . . .
IGenerische Arrays erzeugen overhead:“You can expect accesses to generic arrays to be three to four times slower than accesses to primitive or object arrays.”
RP SS 2019 16 [26]
String
IScala-Strings sindjava . lang . String IUnterstützen aber alle Sequenz-Operationen
IBeste aller Welter: effiziente Repräsentation, viele Operationen
IVergleiche Haskell:typeString= [ Char ]bzw.ByteString
IWird erreicht durch implizite KonversionenStringtoWrappedString undStringtoStringOps
RP SS 2019 17 [26]
Vergleiche von Collections
ICollections sind in Mengen, Maps und Sequenzen aufgeteilt.
ICollections aus verschiendenen Kategorien sind niemals gleich:
Set (1 ,2 ,3) == L i s t (1 ,2 ,3) // false
IMengen und Maps sind gleich wenn sie die selben Elemente enthalten:
TreeSet (3 ,2 ,1) == HashSet(2 ,1 ,3) // true
ISequenzen sind gleich wenn sie die selben Elemente in der selben Reihenfolge enthalten:
L i s t (1 ,2 ,3) == Stream(1 ,2 ,3)// true
RP SS 2019 18 [26]
Scala Collections by Example - Part I
IProblem: Namen der erwachsenen Personen in einer Liste case class Person(name: String , age : Int )
val persons = L i s t (Person("Homer",39) , Person("Marge",34) , Person("Bart",10) , Person(" Lisa ",8) , Person("Maggie",1) , Person("Abe",80) )
ILösung:
val adults = persons . f i l t e r (_. age ≥ 18) .map(_.name)
> L i s t ("Homer", "Marge", "Abe")
RP SS 2019 19 [26]
Scala Collections by Example - Part II
IProblem: Fibonacci Zahlen so elegant wie in Haskell?
f i b s = 0 : 1 : zipWith (+) f i b s ( t a i l f i b s ) ILösung:
val f i b s : Stream [ BigInt ] =
BigInt (0)#: : BigInt (1)#: : f i b s . zip ( f i b s . t a i l ) .map(
n⇒ n ._1 + n ._2) f i b s . take (10) . foreach ( p r i n t l n )
> 0
> 1
> . . .
> 21
> 34
RP SS 2019 20 [26]
Option[+A]
IHabenmaximal1 Element sealed t r a i t Option[+A]
case object Noneextends Option [ Nothing ] case class Some( get : A) extends Option [A]
IEntsprechenMaybein Haskell
ISollten dort benutzt werden wo in Javanullim Spiel ist def get (elem : String ) = elemmatch{
case "a"⇒ Some(1)
case "b"⇒ Some(2)
case_⇒ None }
IHilfreich dabei:
Option(" Hallo ") // Some("Hallo") Option(null) // None
RP SS 2019 21 [26]
Option[+A]
IAn vielen Stellen in der Standardbücherei gibt es die Auswahl:
val ages = Map("Homer"→ 39 , "Marge"→ 34) ages ("Bart") // NoSuchElementException ages . get ("Bart") // None
INützliche Operationen aufOption
val x : Option [ Int ] = ???
x getOrElse 0
x foldLeft ("Test") (_. toString ) x e x i s t s (_ == 4)
. . .
RP SS 2019 22 [26]
Ranges
IRepräsentieren Zahlensequenzen
class Range( s t a r t : Int , end : Int , step : Int )
class I n c l u s i v e ( s t a r t : Int , end : Int , step : Int ) extends Range( start , end + 1 , step )
IIntist “gepimpt” (RichInt):
1 to 10 // new Inclusive(1,10,1) 1 to (10 ,5) // new Inclusive(1,10,5) 1 u n t i l 10// new Range(1,10) IWerte sind berechnet und nicht gespeichert IKeine “echten” Collections
IDienen zum effizienten Durchlaufen von Zahlensequenzen:
(1 to 10) . foreach ( p r i n t l n )
RP SS 2019 23 [26]
For Comprehensions
IIn Scala istfornur syntaktischer Zucker for ( i← 1 to 10) p r i n t l n ( i )
⇒ (1 to 10) . foreach ( i ⇒ p r i n t l n ( i ) ) for ( i← 1 to 10) yield i ∗ 2
⇒ (1 to 10) .map( i ⇒ i ∗ 2)
for ( i← 1 to 10 i f i > 5) yield i ∗ 2
⇒ (1 to 10) . f i l t e r ( i ⇒ i > 5) .map( i ⇒ i ∗ 2) for (x← 1 to 10 , y← 1 to 10) yield (x , y)
⇒ (1 to 10) . flatMap(x⇒ (1 to 10) .map(y⇒ (x , y) ) ) IFunktioniert mit allen Typen die die nötige Untermenge der
Funktionen (foreach,map,flatMap,withFilter) implementieren.
RP SS 2019 24 [26]
Scala Collections by Example - Part III
IProblem: Wörter in allen Zeilen in allen Dateien in einem Verzeichnis durchsuchen.
def f i l e s (path : String ) : L i s t [ F i l e ] def l i n e s ( f i l e : F i l e ) : L i s t [ String ] def words( l i n e : String ) : L i s t [ String ]
def find (path : String , p : String⇒ Boolean) = ???
ILösung:
def find (path : String , p : String⇒ Boolean) =for { f i l e← f i l e s (path)
l i n e ← l i n e s ( f i l e )
word← words( l i n e ) i f p(word) } yield word
RP SS 2019 25 [26]
Zusammenfassung
IScala Collections sind ziemlich komplex IDafür sind die Operationen sehr generisch
IEs gibt keine in die Sprache eingebauten Collections:
Die Collections in der Standardbücherei könnte man alle selbst implementieren
IFür fast jeden Anwendungsfall gibt es schon einen passenden Collection Typ
Ifor-Comprehensions sind in Scala nur syntaktischer Zucker
RP SS 2019 26 [26]
Reaktive Programmierung Vorlesung 5 vom 02.05.19
Das Aktorenmodell
Christoph Lüth, Martin Ring
Universität Bremen Sommersemester 2019
17:06:08 2019-07-10 1 [23]
Fahrplan
IEinführung
IMonaden und Monadentransformer INebenläufigkeit: Futures and Promises IAktoren I: Grundlagen
IAktoren II: Implementation IMeta-Programmierung IBidirektionale Programmierung IReaktive Ströme I
IReaktive Ströme II
IFunktional-Reaktive Programmierung ISoftware Transactional Memory IEventual Consistency IRobustheit und Entwurfsmuster ITheorie der Nebenläufigkeit, Abschluss
RP SS 2019 2 [23]
Das Aktorenmodell
IEingeführt von Carl Hewitt, Peter Bishop und Richard Steiger (1973)
IGrundlage für nebenläufige
Programmiersprachen und Frameworks. (Unter anderem Akka)
ITheoretisches Berechnungsmodell
Warum ein weiteres Berechnungsmodell? Es gibt doch schon die Turingmaschine!
RP SS 2019 3 [23]
Die Turingmaschine
“the behavior of the computer at any moment is determined by the symbols which he [the computer] is observing, and his
‘state of mind’ at that moment” — Alan Turing
Tape
. . . .
Read/write head Program
It is “absolutely impossible that anybody who understands the question [What is computation?] and knows Turing’s definition should decide for a different concept.” — Kurt Gödel
RP SS 2019 4 [23]
Die Realität
I3GHz= 3000000000000Hz=⇒Ein Takt = 3,333∗10−10s Ic= 29907920458ms
IMaximaler Weg in einem Takt<0,1m(Physikalische Grenze)
RP SS 2019 5 [23]
Synchronisation
IWährend auf ein Signal gewartet wird, kann nichts anderes gemacht werden
ISynchronisation ist nur in engen Grenzen praktikabel! (Flaschenhals)
RP SS 2019 6 [23]
Der Arbiter
IDie Lösung:Asynchrone Arbiter
Asynchronous Arbiter I1
I2
O1 O2
IWennI1undI2fast (≈2fs) gleichzeitig aktiviert werden, wird entwederO1oderO2aktiviert.
IPhysikalisch unmöglich in konstanter Zeit. Aber Wahrscheinlichkeit, dass keine Entscheidung getroffen wird nimmt mit der Zeit exponentiell ab.
IIdealer Arbiter entscheidet inO(ln(1/)) Ikommen in modernen Computern überall vor
RP SS 2019 7 [23]
Unbounded Nondeterminism
IIn Systemen mit Arbitern kann das Ergebnis einer Berechnung unbegrenztverzögert werden,
Iwird abergarantiertzurückgegben.
INicht modellierbar mit (nichtdeterministischen) Turingmaschinen.
Beispiel
Ein Abiter entscheidet in einer Schleife, ob ein Zähler inkrementiert wird oder der Wert des Zählers als Ergebnis zurückgegeben wird.
RP SS 2019 8 [23]
Das Aktorenmodell
Quantum mechanics indicates that the notion of a universal description of the state of the world, shared by all observers, is a concept which is physically untenable, on experimental grounds. — Carlo Rovelli
IFrei nach der relationalen Quantenphysik Drei Grundlagen
IVerarbeitung ISpeicher IKommunikation
IDie (nichtdeterministische) Turingmaschine ist ein Spezialfall des Aktorenmodells
IEinAktorensystembesteht ausAktoren(Alles ist ein Aktor!)
RP SS 2019 9 [23]
Aktoren
IEin Aktor verarbeitet Nachrichten
Während ein Aktor eine Nachricht verarbeitet kann er I neue Aktoren erzeugen
I Nachrichten an bekannte Aktor-Referenzen versenden I festlegen wie die nächste Nachricht verarbeitet werden soll
IAktor6= ( Thread|Task|Channel|... ) Ein Aktor kann (darf)nicht
I auf globalen Zustand zugreifen I veränderliche Nachrichten versenden
I irgendetwas tun während er keine Nachricht verarbeitet
RP SS 2019 10 [23]
Aktoren (Technisch)
IAktor≈Schleife über unendliche Nachrichtenliste + Zustand (Verhalten)
IBehavior: (Msg,State)→IO State IoderBehavior:Msg→IO Behavior IVerhalten hat Seiteneffekte (IO):
INachrichtenversand
IErstellen von Aktoren
IAusnahmen
RP SS 2019 11 [23]
Verhalten vs. Protokoll
Verhalten
Das Verhalten eines Aktors ist eine seiteneffektbehaftete Funktion Behavior:Msg→IO Behavior
Protokoll
Das Protokoll eines Aktors beschreibt, wie ein Aktor auf Nachrichten reagiert und resultiert implizit aus dem Verhalten.
IBeispiel:
case (Ping , a) =>
p r i n t l n (" Hello ") counter += 1 a ! Pong
(a(Ping,b)→♦b(Pong))
RP SS 2019 12 [23]
Kommunikation
INachrichten sindunveränderlicheDaten,reineFunktionen oder Futures
IDie Zustellung von Nachrichten passiert höchstens einmal (Best-effort)
IWenn z.B. die Netzwerkverbindung abbricht, wird gewartet, bis der Versand wieder möglich ist
IWenn aber z.B. der Computer direkt nach Versand der Nachricht explodiert (oder der Speicher voll läuft), kommt die Nachricht möglicherweise niemals an
IÜber den Zeitpunkt des Empfangs kann keine Aussage getroffen werden (Unbounded indeterminacy)
IÜber die Reihenfolge der Empfangenen Nachrichten wird im Aktorenmodell keine Aussage gemacht (In vielen Implementierungen allerdings schon)
INachrichtenversand6= ( Queue|Lock|Channel|... )
RP SS 2019 13 [23]
Kommunikation (Technisch)
IDer Versand einer NachrichtMan AktorAbewirkt, dass zugenau einemZeitpunkt in der Zukunft, das VerhaltenBvonAmitMals Nachricht ausgeführt wird.
IÜber den ZustandSvonAzum Zeitpunkt der Verarbeitung können wir begrenzte Aussagen treffen:
Iz.B. Aktor-Invariante: Vor und nach jedem Nachrichtenempfang giltP(S)
IBesser: Protokoll
Iz.B. auf Nachrichten des TypsTreagiertAimmer mit Nachrichten des TypsU
RP SS 2019 14 [23]
Identifikation
IAktoren werden überIdentitätenangesprochen Aktoren kennen Identitäten
Iaus einer empfangenen Nachricht Iaus der Vergangenheit (Zustand) Ivon Aktoren die sie selbst erzeugen
INachrichten können weitergeleitet werden
IEine Identität kann zu mehreren Aktoren gehören, die der Halter der Referenz äußerlich nicht unterscheiden kann
IEindeutige Identifikation bei verteilten Systemen nur durch Authentisierungsverfahren möglich
RP SS 2019 15 [23]
Location Transparency
IEine Aktoridentität kann irgendwo hin zeigen IGleicher Thread
IGleicher Prozess IGleicher CPU Kern IGleiche CPU IGleicher Rechner IGleiches Rechenzentrum IGleicher Ort IGleiches Land IGleicher Kontinent IGleicher Planet I...
RP SS 2019 16 [23]
Sicherheit in Aktorsystemen
IDas Aktorenmodell spezifiziert nicht wie eine Aktoridentität repräsentiert wird
IIn der Praxis müssen Identitäten aberserialisierbarsein ISerialisierbare Identitäten sind auchsynthetisierbar IBei Verteilten Systemen ein potentielles Sicherheitsproblem
IViele Implementierungen stellenAuthentisierungsverfahrenund verschlüsselteKommunikation zur Verfügung.
RP SS 2019 17 [23]
Inkonsistenz in Aktorsystemen
IEin Aktorsystem hatkeinenglobalen Zustand (Pluralismus)
IInformationen in Aktoren sind global betrachtetredundant, inkonsistentoderlokal
IKonsistenz6= Korrektheit
IWo nötig müssen duplizierte Informationen konvergieren, wenn
"längere Zeit"keine Ereignisse auftreten (Eventual consistency)
RP SS 2019 18 [23]
Eventual Consistency
Definition
In einem verteilten System ist ein repliziertes Datumschließlich Konsistent, wenn über einen längeren Zeitraum keine Fehler auftreten und das Datum nirgendwo verändert wird
IKonvergente (oder Konfliktfreie) Replizierte Datentypen (CRDTs) garantieren diese Eigenschaft:
I(N,{+}) oder (Z,{+,−}) IGrow-Only-Sets
IStrategien auf komplexeren Datentypen:
IOperational Transformation IDifferential Synchronization
Idazu später mehr ...
RP SS 2019 19 [23]
Fehlerbehandlung in Aktorsystemen
IWenn das Verhalten eines Aktors eine unbehandelte Ausnahme wirft:
IVerhalten bricht ab
IAktor existiert nicht mehr
ILösung: Wenn das Verhalten eine Ausnahme nicht behandelt, wird sie an einen überwachenden Aktor (Supervisor) weitergeleitet
(Eskalation):
IGleiches Verhalten wird wiederbelebt
Ioder neuer Aktor mit gleichem Protkoll kriegt Identität übertragen
Ioder Berechnung ist Fehlgeschlagen
RP SS 2019 20 [23]
"Let it Crash!"(Nach Joe Armstrong)
IUnbegrenzter Nichtdeterminismus ist statisch kaum analysierbar IUnschärfebeim Testen von
verteilten Systemen ISelbst wenn ein Programm
fehlerfrei ist kann Hardware ausfallen
IJe verteilter ein System umso wahrscheinlicher geht etwas schief IDeswegen:
IOffensives Programmieren
IStatt Fehler zu vermeiden, Fehler behandeln!
ITeile des Programms kontrolliert abstürzen lassen und bei Bedarf neu starten
RP SS 2019 21 [23]
Das Aktorenmodell in der Praxis
IErlang (Aktor-Sprache) IEricsson - GPRS, UMTS, LTE IT-Mobile - SMS
IWhatsApp (2 Millionen Nutzer pro Server) IFacebook Chat (100 Millionen simultane Nutzer) IAmazon SimpleDB
I...
IAkka (Scala Framework)
Ica. 50 Millionen Nachrichten / Sekunde Ica. 2,5 Millionen Aktoren / GB Heap
IAmazon, Cisco, Blizzard, LinkedIn, BBC, The Guardian, Atos, The Huffington Post, Ebay, Groupon, Credit Suisse, Gilt, KK, ...
RP SS 2019 22 [23]
Zusammenfassung
IDas Aktorenmodell beschreibtAktorensysteme IAktorensysteme bestehen ausAktoren IAktoren kommunizieren überNachrichten
IAktoren können überall liegen (Location Transparency) IInkonsistenzen können nicht vermieden werden:Let it crash!
IVorteile: Einfaches Modell; keine Race Conditions; Sehr schnell in Verteilten Systemen
INachteile: Informationen müssen dupliziert werden; Keine vollständige Implementierung
RP SS 2019 23 [23]
Reaktive Programmierung Vorlesung 6 vom 27.04.17 ScalaTest and ScalaCheck
Christoph Lüth, Martin Ring Universität Bremen Sommersemester 2019
17:06:09 2019-07-10 1 [23]
Was ist eigentlich Testen?
Myers, 1979
Testing is the process of executing a program or system with the intent of finding errors.
IHier: testen isselektive,kontrollierteProgrammausführung.
IZieldes Testens ist es immer, Fehler zu finden wie:
IDiskrepanz zwischen Spezifikation und Implementation Istrukturelle Fehler, die zu einem fehlerhaften Verhalten führen
(Programmabbruch, Ausnahmen, etc) E.W.Dijkstra, 1972
Program testing can be used to show the presence of bugs, but never to show their absence.
RP SS 2019 2 [23]
Testmethoden
IStatisch vs. dynamisch:
IStatischeTestsanalysierenden Quellcode ohne ihn auszuführen (statische Programmanalyse)
IDynamischeTests führen das Programm unterkontrollierten Bedingungen aus, und prüfen das Ergebnis gegen eine gegebene Spezifikation.
IZentrale Frage: wo kommen dieTestfälleher?
IBlack-box: Struktur des s.u.t. (hier: Quellcode) unbekannt, Testfälle werden aus der Spezifikation generiert;
IGrey-box: Teile der Struktur des s.u.t. ist bekannt (z.B. Modulstruktur) IWhite-box: Struktur des s.u.t. ist offen, Testfälle werden aus dem
Quellcode abgeleitet
RP SS 2019 3 [23]
Spezialfall des Black-Box-Tests: Monte-Carlo Tests
IBei Monte-Carlo oder Zufallstests werdenzufälligeEingabewerte generiert, und das Ergebnis gegen eine Spezifikation geprüft.
IDies erfordertausführbareSpezifikationen.
IWichtig ist dieVerteilungder Eingabewerte.
IGleichverteilt über erwartete Eingaben, Grenzfälle beachten.
IFunktioniert gut mithigh-level-Spachen(Java, Scala, Haskell) IDatentypen repräsentieren Informationen aufabstrakterEbene IEigenschaft gutspezifizierbar
IBeispiel: Listen, Listenumkehr in C, Java, Scala
IZentrale Fragen:
IWie können wirausführbare Eigenschaftenformulieren?
IWieVerteilungder Zufallswerte steuern?
RP SS 2019 4 [23]
ScalaTest
ITest Framework für Scala
import org . s c a l a t e s t . FlatSpec class StringSpecextends FlatSpec {
"A String " should " reverse " in {
" Hello ". reverse should be (" olleH ") }
i t should " return the correct length " in {
" Hello ". length should be (5) }
}
RP SS 2019 5 [23]
ScalaTest Assertions 1
IScalaTest Assertions sind Makros:
importorg . s c a l a t e s t . Assertions ._
val l e f t = 2 val r i g h t = 1 assert ( l e f t == r i g h t )
ISchlägt fehl mit"2 did not equal 1"
IAlternativ:
val a = 5 val b = 2 assertResult (2) {
a−b }
ISchlägt fehl mit"Expected 2, but got 3"
RP SS 2019 6 [23]
ScalaTest Assertions 2
IFehler manuell werfen:
f a i l (" I ’ ve got a bad f e e l i n g about t h i s ") IErwartete Exeptions:
val s =" hi "
val e = intercept [ IndexOutOfBoundsException ] { s . charAt(−1)
}
IAssumptions
assume( database . i s A v a i l a b l e )
RP SS 2019 7 [23]
ScalaTest Matchers
IGleichheit überprüfen:
r e s u l t should equal (3) r e s u l t should be (3) r e s u l t shouldBe 3 r e s u l t shouldEqual 3 ILänge prüfen:
r e s u l t should have length 3 r e s u l t should have s i z e 3 IUnd so weiter...
text should startWith (" Hello ") r e s u l t should be a [ L i s t [ Int ] ] l i s t should contain noneOf (3 ,4 ,5)
ISiehehttp://www.scalatest.org/user_guide/using_matchers
RP SS 2019 8 [23]
ScalaTest Styles
IScalaTest hat viele verschiedene Styles, die über Traits eingemischt werden können
IBeispiel:FunSpec(Ähnlich wie RSpec) class SetSpec extends FunSpec {
describe ("A Set") { describe ("when empty") {
i t ("should have s i z e 0") { assert ( Set . empty . s i z e == 0) }
i t ("should produce NoSuchElementException when head i s invoked") {
intercept [ NoSuchElementException ] { Set . empty . head
} } } } } IÜbersicht unter
http://www.scalatest.org/user_guide/selecting_a_style
RP SS 2019 9 [23]
Blackbox Test
IÜberprüfen eines Programms oder einer Funktion ohne deren Implementierung zu nutzen:
def primeFactors (n : Int ) : L i s t [ Int ] = ???
Iz.B.
"primeFactors" should "work for 360" in {
primeFactors(360) should contain theSameElementsAs L i s t (2 ,2 ,2 ,3 ,3 ,5)
}
IWas ist mit allen anderen Eingaben?
RP SS 2019 10 [23]
Property based Testing
IÜberprüfen vonEigenschaften(Properties) eines Programms / einer Funktion:
def primeFactors (n : Int ) : L i s t [ Int ] = ???
IWir würden gerne so was schreiben:
f o r a l l x ≥ 1→ primeFactors (x) . product = x
&& primeFactors (x) . f o r a l l ( isPrime )
IAber wo kommen die Eingaben her?
RP SS 2019 11 [23]
Testen mit Zufallswerten
Idef primeFactors (n : Int ) : L i s t [ Int ] = ???
IZufallszahlen sind doch einfach!
"primeFactors" should "work for many numbers" in { (1 to 1000) foreach { _⇒
val x = Math.max(1 , Random. nextInt . abs) assert ( primeFactors (x) . product == (x) ) assert ( primeFactors (x) . f o r a l l ( isPrime ) ) }
}
IWas ist mit dieser Funktion?
defsum( l i s t : L i s t [ Int ] ) : Int = ???
RP SS 2019 12 [23]
ScalaCheck
IScalaCheck nutzt Generatoren um Testwerte für Properties zu generieren
f o r A l l { ( l i s t : L i s t [ Int ] ) ⇒ sum( l i s t ) == l i s t . foldLeft (0) (_ + _) }
IGeneratoren werden über implicits aufgelöst ITypklasseArbitraryfür viele Typen vordefiniert:
abstract class Arbitrary [T] { val a r b i t r a r y : Gen[T]
}
RP SS 2019 13 [23]
Zufallsgeneratoren
IEin generischer Zufallsgenerator:
t r a i t Generator[+T] {def generate : T } object Generator {
def apply [T] ( f :⇒ T) =newGenerator [T] { def generate = f }
}
Ival integers = Generator (Random. nextInt )
Ival booleans = Generator ( integers . generate > 0)
Ival p a i r s =
Generator (( integers . generate , integers . generate ) )
RP SS 2019 14 [23]
Zufallsgeneratoren Kombinieren
IEin generischer,kombinierbarerZufallsgenerator:
t r a i t Generator[+T] { s e l f ⇒ def generate : T
defmap[U] ( f : T⇒U) =newGenerator [U] { def generate = f ( s e l f . generate ) }
def flatMap [U] ( f : T⇒ Generator [U] ) =newGenerator [U] { def generate = f ( s e l f . generate ) . generate
} }
RP SS 2019 15 [23]
Einfache Zufallsgeneratoren
IEinelementige Wertemenge:
def s i n g l e [T] ( value : T) = Generator ( value ) IEingeschränkter Wertebereich:
def choose( lo : Int , hi : Int ) = integers .map(x⇒ lo + x % ( hi−lo ) ) IAufzählbare Wertemenge:
def oneOf [T] ( xs : T∗) : Generator [T] = choose (0 , xs . length ) .map( xs )
RP SS 2019 16 [23]