• Keine Ergebnisse gefunden

Warum Reaktive Programmierung?

N/A
N/A
Protected

Academic year: 2022

Aktie "Warum Reaktive Programmierung?"

Copied!
60
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

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]

(2)

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]

(3)

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 :ABmit Seiteneffekt inZustandS:

f :A×SB×S

∼= f :ASB×S

IDatentyp:SB×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]

(4)

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]

(5)

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]

(6)

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]

(7)

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]

(8)

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]

(9)

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]

(10)

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]

(11)

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]

(12)

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]

(13)

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]

(14)

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]

(15)

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]

(16)

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]

(17)

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]

(18)

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:MsgIO 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:MsgIO 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]

(19)

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]

(20)

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]

(21)

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]

Referenzen

ÄHNLICHE DOKUMENTE

I Cold Observables fangen erst an Werte zu produzieren, wenn man ihnen zuhört.. Für jeden Observer

[r]

Calling onSubscribe, onNext, onError or onComplete MUST return normally except when any provided parameter is null in which case it MUST throw a java.lang.NullPointerException to

I Werte vom Typ IO (Aktionen) können kombiniert werden wie alle anderen. I

[r]

I Nachdem onCompleted oder onError aufgerufen wurde wird onNext nicht mehr

I Wenn der Konsument keine Daten mehr annehmen kann soll der Produzent aufhören sie zu Produzieren. I Erste Idee: Wir können den produzierenden

[r]