Reactive programming principles
-
Upload
riccardo-cardin -
Category
Software
-
view
603 -
download
0
description
Transcript of Reactive programming principles
PRINCIPI DI REACTIVE PROGRAMMINGINGEGNERIA DEL SOFTWAREUniversità degli Studi di Padova
Dipartimento di Matematica
Corso di Laurea in Informatica, A.A. 2013 – 2014
2
Ingegneria del software mod. B
GO REACTIVE!
Applicazione anni 2000 Decine di server Tempi di risposta nell’ordine dei secondi Ore di downtime per manutenzione Dati nell’ordine dei Gigabyte Accedute da dispositivi desktop
Applicazione moderne (≥ 2010) Cluster di migliaia di processi multicore Tempi di risposta nell’ordine dei millisec 100% uptime Dati nell’ordine dei Petabyte Accedute da qualsiasi tipo di dispositivo
Riccardo Cardin
3
Ingegneria del software mod. B
GO REACTIVE!
Nuovi requisiti richiedono nuove tecnologie Reactive Application
Orientate agli eventi Scalabili Resilienti Responsive
Riccardo Cardin
"Readily responsive to a stimulus"Merriam-Webster
react to eventsLa natura event-driven abilita
alle altre qualità
react to loadLa scalabilità non deve dipendere
da risorse condivise
react to failureSistemi resilienti permettonodi recuperare errori a tutti
i livelli
react to usersI tempi di risposta non devonodipendere dal carico di lavoro
4
Ingegneria del software mod. B
REACTIVE MANIFESTO
Riccardo Cardin
responsive
scalable resilient
event-driven
• Loosely coupled design• Communication
orientation• Uso efficiente delle risorse
• Nessun redesing per ottenere la scalabilità
• Scalabilità on-demand
• Risk-management
• Downtime è perdita di denaro
• Parte del design
• Real-time, engaging, reach, collaborative
• Nessuna latenza nelle risposte
5
Ingegneria del software mod. B
MODELLO SINCRONO
Il mondo sincrono è senza futuro...
Frequenti operazioni di I/O Scarso utilizzo delle feature offerte dai processori
moderni Larga diffusione delle architetture multiprocessore
Cicli non ottimizzati Scarso parallelismo o gestione difficoltosa Tipico dei linguaggi imperativi e ad oggetti
C, C++, Java, ...
Riccardo Cardin
// Synchronous world (w/o Future)val session = socialNetwork.createSessionFor("user", credentials)// blocked on method, waiting for results (latency)...session.getFriends()// There are a lot of operation to do!!! :(
6
Ingegneria del software mod. B
MODELLO SINCRONO
Il mondo sincrono è senza futuro... Esempio: recuperare il nome del file più pesante
Riccardo Cardin
public String getBiggestFile(final File folder) { long maxLength = 0L; String fileName = null; for (final File fileEntry : folder.listFiles()) { if (maxLength < fileEntry.length()) { // Not so efficient fileName = fileEntry.getName(); maxLength = fileEntry.length(); } } return fileName ;}
...
if (maxLength… // computationfileEntry.length() // I/O
CPU poco utilizzata, I/O
sovrabbondante
Java
Tempo totale di attesa
7
Ingegneria del software mod. B
MODELLO ASINCRONO
Callbacks Funzioni da invocare al termine di una
elaborazione Gestione migliore della CPU Ridotti tempi di attesa
Più processi gestiscono più richieste Asynchronous JavaScript and XML (AJAX)
Riccardo Cardin
var callback = function(){ alert('I was called back asynchronously');};
$.ajax({ type: 'GET', url: 'http://example.com', done: callback, // positive case fail: anotherCallback // negative case}); jQuery
In attesa della risposta, è possibile continuare
l’elaborazione (rendering UI)
8
Ingegneria del software mod. B
MODELLO ASINCRONO
Callbacks
Linguaggi o framework che gestiscano l’elaborazione asincrona e concorrente Node.js, jQuery, ...
Ma...c’è sempre un ma...
Riccardo Cardin
CPU1
CPU2
CPU3
CPU4
Tempo totale di attesa
I/O è ancora presente, ma viene distribuito
sull’elaborazione di più CPU
9
Ingegneria del software mod. B
MODELLO ASINCRONO
Callbacks...HELL!!!
Riccardo Cardin
10
Ingegneria del software mod. B Riccardo Cardin
module.exports = function (dir, cb) { fs.readdir(dir, function (er, files) { if (er) return cb(er) var counter = files.length var errored = false var stats = [] files.forEach(function (file, index) { fs.stat(path.join(dir,file), function (er, stat) { if (errored) return if (er) { errored = true return cb(er) } stats[index] = stat if (--counter == 0) { var largest = stats .filter(function (stat) { return stat.isFile() }) .reduce(function (prev, next) { // [6] if (prev.size > next.size) return prev return next }) cb(null, files[stats.indexOf(largest)]) } }) // [1] }) // [2] }) // [3]}
node.js
Innesto callback per gestire i flussi degli eventi
Difficile da verificare e manutenere
Difficile gestire le eccezioni con blocchi
try/catch
11
Ingegneria del software mod. B
FUTURES E PROMISES
Futures Tecnica per eseguire molte operazioni in
parallelo, in modo efficiente e non-blocking Stile dichiarativo Immutabile
Rappresenta un segnaposto per un risultato futuro Componibili Implementano meccanismi per la gestione delle
eccezioni
Riccardo Cardin
// With Futures (asynchronous world)val session = socialNetwork.createSessionFor("user", credentials)// Create placeholder for computationval f: Future[List[Friend]] = future { session.getFriends() }// Statements here can be executed, while waiting for results :)
scala
12
Ingegneria del software mod. B
FUTURES E PROMISES
Monad Rappresenta un contesto di esecuzione
(framework) Amplificatore di tipi, computation builder Può racchiudere un tipo
È componibile con altre monadi Composizione (a.k.a. concatenazione) sul tipo
racchiuso
Spesso permette di estrarre il valore del tipo contenuto Caratteristica dei linguaggi funzionali
Riccardo Cardin
public class Monad<T> { public Monad(T t) { /* ... */ }}
public class Monad<T> { public abstract <V> Monad<V> bind(Function<T, Monad<V>> f);}
13
Ingegneria del software mod. B
FUTURES E PROMISES
Monad È simile ad una bolla!
Riccardo Cardin
Può racciudere qualcosa
È qualcosa di non concreto
Può ricevere istruzioni su cosa fare del
contenuto
Può evaporare, lasciando libero il
contenuto
14
Ingegneria del software mod. B
FUTURES E PROMISES
Future[T] è una monad Racchiudono l’elaborazione da eseguire in modo
asincrono (callback) Successfully completed / Failed with an exception Eventual execution: nessun vincolo temporale
Riccardo Cardin
import scala.util.{Success, Failure}// Asynchronous execution inside future contextval f: Future[List[String]] = future { session.getRecentPosts}// Do something else...f onComplete { // onSuccess case Success(posts) => for (post <- posts) println(post) // onFailure case Failure(t) => println("An error has occured: " + t.getMessage)}
posts è il risulato dell’elaborazione
t è un’eccezione scala
15
Ingegneria del software mod. B
FUTURES E PROMISES
Future[T] è una monad Composizione funzionale di più elaborazioni
Non più callback hell!!! Si riporta il modello asincrono al modello sincrono Se un future nella catena fallisce, fallisce l’intera
catena
Riccardo Cardin
// First future executionval rateQuote = future { connection.getCurrentValue(USD)}// Bind second execution to firstval purchase = rateQuote map { quote => if (isProfitable(quote)) connection.buy(amount, quote) else throw new Exception("not profitable")}// Get final resultpurchase onSuccess { case _ => println("Purchased " + amount + " USD")} scala
16
Ingegneria del software mod. B
FUTURES E PROMISES
Promise[T] Single-assigment container (monad) / proxy
Un Future legge il risultato di un’elaborazione asincrona
Una Promise scrive (completa) un Future
Riccardo Cardin
val p = promise[T]// Future that is completed by the promiseval f = p.futureval consumer = future { startDoingSomething() f onSuccess { case r => doSomethingWithResult() }}val producer = future { val r = produceSomething() p success r // Promise completes the Future // It should be ‘p failure exception’ also continueDoingSomethingUnrelated()}
produceSomething
startDoingSomething
doSomethingWithResult
r
scala
Valore che rappresenta
l’elaborazione
17
Ingegneria del software mod. B
FUTURES E PROMISES
Javascript promises (Q library) Promise e future sono fusi nelle medesime
strutture
Promise stile Scala Q Deferreds
Riccardo Cardin
promiseMeSomething()// value is the return value of promiseMeSomething.then(function (value) { // Do something as soon as promiseMeSomething finishes}, // Something went wrong, reason is an exception function (reason) {});
then ritona una promise, quindi è
concatenabile
var deferred = Q.defer();FS.readFile("foo.txt", "utf-8", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise; Deferred permette di
completare una promise. concatenabile
18
Ingegneria del software mod. B
FUTURES E PROMISES
Java 8 promises: CompletableFuture<T>
Creazione (usando le lambda extension)
Composizione (future stile Scala)
Riccardo Cardin
A Future that may be explicitly completed (setting its value and status), and may include dependent functions and actions that trigger upon its completion.
Javadoc
final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { //...long running... return "42"; }, executor);
Effettua l’override del metodo
CompletableFuture.get()
// f1 is a promise that will completed with an Integer valueCompletableFuture<Double> f3 = f1.thenApply(Integer::parseInt).thenApply(r -> r * r * Math.PI). exceptionally(ex -> "We have a problem: " + ex.getMessage());
thenApply è simile a map di Scala
19
Ingegneria del software mod. B
REACTIVE EXTENSIONS (RX)
Gestione sequenze di valori in modo asincrono Observable sequences
Estensione del design pattern Observer Utilizzo di operatori di composizione (monads!)
Riccardo Cardin
Single items Multiple items
Synchronous T getData() Iterable<T> getData()
Asynchronous Future<T> getData() Observable<T> getData
public static void hello(String... names) { Observable.from(names).subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println("Hello " + s + "!"); } });} // hello("Ben", "George"); Hello Ben! Hello George!
20
Ingegneria del software mod. B
REACTIVE EXTENSIONS (RX)
Observables (RxJava)
Riccardo Cardin
Event Iterable (pull) Observable (push)
Retrieve data T next() onNext(T)
Discover error throws Exception
onError(Exception)
Complete returns onCompleted()
Aggiunta al pattern
GoF
getVideos().subscribe(new Observer<Video>() { def void onNext(Video video) { // Invoked on next element println(“Video: ” + video.videoId) } def void onError(Exception e) { // Invoked on error e.printStackTrace() } def void onCompleted() { // Invoked when stream finishes to emit println(“Completed”) }}
21
Ingegneria del software mod. B
REACTIVE EXTENSIONS (RX)
Observables (RxJava) Monads Componibili
Mantengono la proprietà di asincronia originaria
Riccardo Cardin
22
Ingegneria del software mod. B
REACTIVE EXTENSIONS (RX)
Composizione Observables
Riccardo Cardin
23
Ingegneria del software mod. B
ACTOR MODEL
Reactive Elaborazioni solo in risposta a stimoli esterni
Dormiente / attivo Non c’è un concetto esplicito di thread
Tre azioni fondamentali Invio di un messaggio async a se stesso o altro
attore Creazione nuovi attori Modifica del proprio comportamento
Nessuno stato interno (...in teoria...) ImmutabiliRiccardo Cardin
Each actor is a form of reactive object, executing some computation in response to a message and sending out a reply when the computation is done
John C. Mitchell
24
Ingegneria del software mod. B
ACTOR MODEL
Messaggi (task) Interfaccia di comunicazione dell’attore
Variare nel tempo (comportamento) Elaborazione dei messaggi uno per volta
Coda di messaggi (mail box) Nessuna garanzia sull’ordine di arrivo
Mail system Ogni attore ha associato un mail address
Composti di tre parti
Riccardo Cardin
tag target data
email address del receiver
operazione
25
Ingegneria del software mod. B
ACTOR MODEL
Esempio Ad ogni cambio di stato viene creato un nuovo
attore State change: no race conditions Behavioural change
Riccardo Cardin
A1:[1, 4, 7]
A1:[1, 2, 4, 7]
A1:[2, 4, 7]
Insert|2
Get_min
Min|1
26
Ingegneria del software mod. B
ACTOR MODEL
Akka Toolkit e runtime che implementano attori su JVM
Riccardo Cardin
(c) http://akka.io
27
Ingegneria del software mod. B
AKKA
Riccardo Cardin
type Receive = PartialFunction[Any, Unit]trait Actor { def receive: Receive // Actor actual behaviour implicit val self: ActorRef // Reference to itself def sender: ActorRef // Reference to the sender of last message implicit val context: ActorContext // Execution context}abstract class ActorRef { // Send primitives def !(msg: Any)(implicit sender: ActorRef = Actor.noSender): Unit def tell(msg: Any, sender: ActorRef) = this.!(msg)(sender) // ...}trait ActorContext { // Change behaviour of an Actor def become(behavior: Receive, discardOld: Boolean = true): Unit def unbecome(): Unit // Create a new Actor def actorOf(p: Props, name: String): ActorRef def stop(a: ActorRef): Unit // Stop an Actor // ...}
scala
28
Ingegneria del software mod. B
AKKA
Esempio Implementazione di un contatore con gli attori
Riccardo Cardin
class Counter extends Actor { // State == explicit behaviour def counter(n: Int): Receive = { // Receive two types of messages: ‘incr’ and ‘get’ // ‘incr’ change actor’s behaviour case ”incr” => context.become(counter(n + 1)) // ‘get’ returns current counter value to sender case ”get” => sender ! n } def receive = counter(0) // Default behaviour} scala
a:[0]
a!incr
a:[1]
a!incr
a:[2]
a!get sender!2
È possibile modellare
anche stati
interni
29
Ingegneria del software mod. B
AKKA
Resilienza Contenimento e riposte automatiche agli errori
Gli attori in errore vengono terminati o riavviati La decisione è presa da un attore supervisore Gli attori con supervisione formano una struttura ad
albero Il supervisore crea i suoi subordinati
Riccardo Cardin
class Manager extends Actor { // OneForOneStrategy restarts only actor which died override val supervisorStrategy = OneForOneStrategy() { case _: DBException => Restart // reconnect to DB case _: ActorKilledException => Stop case _: ServiceDownException => Escalate } // ... context.actorOf(Props[DBActor], ”db”) // ...}
sup
sub1
sub2
sub1.1Error flow
30
Ingegneria del software mod. B
AKKA
Actor lifecycle
Riccardo Cardin
Start
Restart
Stop
new ActorpreStart
fail
preStartnew Actor
stop
postStop
Supervisor
An actor
ActorRef rimane valido tra un
riavvio e l’altro
Le fasi di riavvio possono essere
molteplici
31
Ingegneria del software mod. B
BIBLIOGRAFIA The Reactive Manifesto
http://www.reactivemanifesto.org/ Promises in Node.js with Q – An Alternative to Callbacks
http://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/
The Reactive Extensions (Rx) http://msdn.microsoft.com/en-us/data/gg577609.aspx
Futures and Promises http://docs.scala-lang.org/overviews/core/futures.html
Java concurrency (multi-threading) http://www.vogella.com/tutorials/JavaConcurrency/article.html#futures
Java 8: Definitive guide to CompletableFuture http://nurkiewicz.blogspot.it/2013/05/java-8-definitive-guide-to.html
Taming asynchronous programming http://eamodeorubio.github.io/tamingasync/#/
Riccardo Cardin
32
Ingegneria del software mod. B
BIBLIOGRAFIA Monadic futures in Java 8
http://zeroturnaround.com/rebellabs/monadic-futures-in-java8/
Monads http://ericlippert.com/category/monads/ Callback Hell http://callbackhell.com/ CompletableFuture http://
www.slideshare.net/kojilin/completable-future RxJava Wiki https://github.com/Netflix/RxJava/wiki Functional Reactive Programming with RxJava https://
speakerdeck.com/benjchristensen/functional-reactive-programming-with-rxjava-javaone-2013
Principle of Reactive Programming https://class.coursera.org/reactive-001
Actors http://doc.akka.io/docs/akka/snapshot/scala/actors.html
Riccardo Cardin