Asynchronous Scala
April 2015, Javier Santos
Promising futures...
Foto emotiva
relacionada con lo que
vamos a contar
Javier Santos PaniegoScala Developer
CONTACT
INTRODUCTION
• Functional World
• Runnable/Callable
• Threads
1 2 3FUTURES
• Completion
• ExecutionContext
• Callbacks
• Future monad
• Composition
• Recovery
PROMISES
• Baggage & Claim
• Completion
INDEX
Asynchronous Scala: Promising futures
● Purely functional: whole world could be implemented in a single functional line
● Functional features○ Robust○ Debuggable○ Predictable○ Pluggable
Introduction
A functional world
Asynchronous Scala: Promising futures
● Example
type Context = (Input,Output,Error)type Action = Context => (Context,Event)
def main(
actions: Iterable[Action], context: Context):(Context,Seq[Event]) = {
((context,Seq.empty[Event]) /: actions) {
case ((context,events),actions) =>
action.apply(context) match {
case (context,event) => (context, events :+ event)
}
}
}
Introduction
A functional world
Asynchronous Scala: Promising futures
● Problem? World actions are not precalculated. What happens to I/O?
● World can be considered as○ asynchronous: Things may happen at same time○ reactive: Things may happen due to
■ actions: that trigger …■ ...events: action consequences.
Introduction
A functional world
Asynchronous Scala: Promising futures
● java.lang.Runnable
trait Runnable {
def run(): Unit
}
● java.util.concurrent.Callable
trait Callable[V] {
def call(): V
}
Introduction
Runnable & Callable
Asynchronous Scala: Promising futures
● Scala’s concurrency model is built on Java’s● java.lang.Thread
val myThread = new Thread(new Runnable {
def run(){
println(“hi”)
}
}
myThread.start()
Introduction
Threads
Asynchronous Scala: Promising futures
● Thread improvements○ ExecutorService (obtained from static Executors) allows using
thread policies (like threading pools)
val pool: ExecutorService = Executors.newFixedThreadPool(poolSize)
pool.execute(new Runnable{
def run(){
println(“I’m handling a request”)
}
})
○ Anyway, Threads abstraction level is too low
Introduction
Thread policies
Asynchronous Scala: Promising futures
● By default, non-blocking operations● They will hold a T value at some point● So a future may be uncompleted(it has no value yet) or completed● Completion will be treated as a scala.util.Try value
It will have two possible values:○ Success(t: T)○ Failure(t: Throwable)
Futures
Overview
Asynchronous Scala: Promising futures
● Successfully completion example
import scala.concurrent._import ExecutionContext.Implicits.global
val firstPrimeNumbers: Future[List[Int]] = Future { List(1,2,3,5,7,11,13)
//what if 'calculateFirstPrimeNumbers(100000)'…
}
res0: Future[List[Int]]
Futures
Success on completion
Asynchronous Scala: Promising futures
● Failure completion example
import scala.concurrent._import ExecutionContext.Implicits.global
val thisWillFail: Future[Int] = Future(2 / 0)
res0: Future[Int]
Futures
Failure on completion
Asynchronous Scala: Promising futures
● A future, once it’s completed, it never changes of value
● An ExecutionContext ○ executes tasks submitted to them.○ They can be seen as thread pools.○ Most of future ops require an implicit ExecutionContext.
Futures
ExecutionContext
Asynchronous Scala: Promising futures
● Expecting results.
○ Blocker way (discouraged but sometimes mandatory).
○ Non-blocker way: using callbacks
Futures
Expecting results
Asynchronous Scala: Promising futures
● Blocking: Await.result / Await.ready
import scala.concurrent._import scala.concurrent.duration._import scala.concurrent.ExecutionContext.Implicits.global
val f: Future[Int] = Future{ Thread.sleep(10000) 2}
println(Await.result(f,12.seconds))//2
Futures
Blocking: Await
Asynchronous Scala: Promising futures
● Blocking: Await (Problem: Not enough time)
import scala.concurrent._import scala.concurrent.duration._import scala.concurrent.ExecutionContext.Implicits.global
val f: Future[Int] = Future{ Thread.sleep(10000) 2}
println(Await.result(f,5.seconds))java.util.concurrent.TimeoutException: Futures timed out after [5 seconds]
Futures
Blocking: Await problem
Asynchronous Scala: Promising futures
● Non-Blocking: callbacks
import scala.concurrent._import scala.concurrent.duration._import scala.concurrent.ExecutionContext.Implicits.global
val f: Future[Int] = Future{ Thread.sleep(10000) 2}
f.onComplete( n => println(n) )
//at some point, “Success(2)” will appear
Futures
Non-blocking: Callbacks
Non-blocking
Asynchronous Scala: Promising futures
● Callbacks will be executed asynchronously when future is completed
● Try[T] => U
● Try[T] ~ Either[Throwable,T]○ Left(throwable) ~ Failure(throwable)○ Right(t) ~ Success(t)
Futures
Callbacks
Asynchronous Scala: Promising futures
● onCompletef.onComplete( (t: Try[Int]) => println(n) )//Success(2)
● onSuccessf.onSuccess( n => println(n) )//2
● onFailuref.onFailure( throwable => println(throwable.getMessage) )//it will never print an error (because it equals Success(2))
Futures
Callbacks
Asynchronous Scala: Promising futures
● Composition○ Future is a monad
■ Type Constructor: T => Future[T]■ Unit Function: Future.apply■ Bind Function: flatMap
○ Since Future has map,flatMap,filter methods; it can be composed easily in a for-comprehension
Futures
Monad behavior
Asynchronous Scala: Promising futures
● map
def getFirstMillionOfPrimes(): Future[List[Int]] = ???
getFirstMillionOfPrimes().map( (list: List[Int]) => list.head)
res0: Future[Int]
Futures
Monad behavior
Asynchronous Scala: Promising futures
● flatMap
def getFirstMillionOfPrimes(): Future[List[Int]] = ???
def concatenate(l: List[Int]): Future[String] = ???
getFirstMillionOfPrimes().flatMap((list: List[Int]) => concatenate(list))
res0: Future[String]
Futures
Monad behavior
Asynchronous Scala: Promising futures
● Problem
var result: String = “”val f1: Future[Unit] = Future{result += “Hi ”}val f2: Future[Unit] = Future{result += “ everyone”}
● result value?
Futures
Composition
Asynchronous Scala: Promising futures
● for-comprehension is your friend
for { primes <- getFirstMillionPrimes() primesString <- concatenate(primes)} yield primes
res0: Future[String]
Futures
Composition
Future[List[Int]]
Future[String]
Asynchronous Scala: Promising futures
● recover
val f: Future[Int] = Future{ 1 / 0 }.recover{ case e: ArithmeticException => 0}
Futures
Recovering from failure
Asynchronous Scala: Promising futures
● recoverWith
val f: Future[Int] = Future{ 1 / 0 }.recoverWith{ case e: ArithmeticException => Future(0)}
Futures
Recovering from failure
Asynchronous Scala: Promising futures
● fallbackTo
val f1: Future[Int] = Future{ 1 / 0 }val f2: Future[Int] = Future(0)
val f = f1 fallbackTo f2
Futures
Recovering from failure
Asynchronous Scala: Promising futures
● Futures can be created by○ Future.apply○ Promises
● You can think about it like○ Future ~ Read future value○ Promise ~ Write future value
● Promises are single-assigned (just once. Immutable as futures)
Promises
Overview
Asynchronous Scala: Promising futures
Promises
Baggage & claim pattern
Menuorder
MenuBeing
Cooked
Ticket
MenuReady
Asynchronous Scala: Promising futures
Promises
Baggage & claim pattern
Promise[T]
Begincompletion
Future[T]
p.successor
p.failure
Try[T]
Asynchronous Scala: Promising futures
Promises
Example
val producer = future {
val r: T = produceSomething()
p success r
continueDoingSomethingUnrelated()
}
val consumer = future {
startDoingSomething()
f onSuccess {
case r: T => handleResult()
}
}
val p = promise[T]
val f = p.future
Asynchronous Scala: Promising futures
● complete
val p: Promise[Int]p.complete(Try(2))
● completeWith
val p: Promise[Int]p.completeWith(Future(2))
Promises
Overview
Still interested?
● Scala school (Twitter) ● Reactive Design Patterns, Roland
Kuhn and Jamie Allen● Scala-lang docs: Futures and
promises● Akka doc - Futures