the future starts with a promise
TRANSCRIPT
![Page 2: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/2.jpg)
The Future Starts with a Promise
● Dumb title ● The Future starts whether we want it or not
![Page 3: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/3.jpg)
Performance
“amount of useful work accomplished by a computer system compared to the time and
resources used”
![Page 4: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/4.jpg)
Performance
Currency for things we want
![Page 5: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/5.jpg)
What we want
● Productivity● Scalability● Throughput● Resiliency● Low infrastructure costs● ...
![Page 6: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/6.jpg)
CPU boundvs
I/O bound
![Page 7: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/7.jpg)
Latency Comparison Numbersgist.github.com/jboner/2841832
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns 14x L1
Mutex lock/unlock 25 ns
Main memory reference 100 ns 20x L2, 200x L1
Compress 1K bytes with Zippy 3,000 ns
Send 1K bytes over 1 Gbps network 10,000 ns
Read 4K randomly from SSD* 150,000 ns
Read 1 MB sequentially from memory 250,000 ns
Round trip within same datacenter 500,000 ns
Read 1 MB sequentially from SSD* 1,000,000 ns 4X memory
Disk seek 10,000,000 ns
Read 1 MB sequentially from disk 20,000,000 ns 80x memory, 20X SSD
Send packet CA>Netherlands>CA 150,000,000 ns
![Page 8: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/8.jpg)
Optimizing I/O bound operations
● For scalability the whole workflow must be based on asynchronous I/O– E.g. Slowloris HTTP DoS
– All Java Servlet Containers (up until Servlets 3.1) are vulnerable
● Must avoid blocking threads in a limited thread-pool
![Page 10: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/10.jpg)
Example of Common Patternvar result = "Not Initialized"
var isDone = false
val producer = new Thread(new Runnable {
def run() {
result = "Hello, World!"
isDone = true
}
})
val consumer = new Thread(new Runnable {
def run() {
// loops until isDone is true
while (!isDone) {}
println(result)
}
})
![Page 11: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/11.jpg)
Example of Common Patternvar result = "Not Initialized"
var isDone = false
val producer = new Thread(new Runnable {
def run() {
result = "Hello, World!"
isDone = true
}
})
val consumer = new Thread(new Runnable {
def run() {
// loops until isDone is true
while (!isDone) {}
println(result)
}
})
What does it print?a) Hello world!
b) Not initialized
c) Nothing (infinite loop)
![Page 12: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/12.jpg)
Example of Common Pattern
What does it print?a) Hello world!
b) Not initialized
c) Nothing (infinite loop)
d) All of the above
var result = "Not Initialized"
var isDone = false
val producer = new Thread(new Runnable {
def run() {
result = "Hello, World!"
isDone = true
}
})
val consumer = new Thread(new Runnable {
def run() {
// loops until isDone is true
while (!isDone) {}
println(result)
}
})
![Page 13: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/13.jpg)
Example of Common Pattern
var result = "Not Initialized"
var isDone = false
val lock = new AnyRef
val producer = new Thread(new Runnable {
def run() {
lock.synchronized {
result = "Hello, World!"
isDone = true
}
}
})
val consumer = new Thread(new Runnable {
def run() {
var exitLoop = false
while (!exitLoop)
lock.synchronized {
if (isDone) {
println(result)
exitLoop = true
}
}
}
})
![Page 14: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/14.jpg)
Locks
● Locks break encapsulation● Locks do not compose● It's easy to make mistakes
– Acquiring too few
– Acquiring too many
– Acquisition in the wrong order
![Page 15: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/15.jpg)
java.util.concurrent.Future
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
(since Java 1.5)
![Page 16: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/16.jpg)
java.util.concurrent.Future
import java.util.concurrent.{Callable, Executors, Future}
val pool = Executors.newCachedThreadPool()
// nonblocking
val future: Future[String] =
pool.submit(new Callable[String] {
def call() = {
// process and return something
"Hello World!"
}
})
// blocks, waiting for result...
val result = future.get()
println(result)
pool.awaitTermination(1, TimeUnit.SECONDS)
![Page 17: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/17.jpg)
java.util.concurrent.Future
● Good API encapsulation● General concept, the executor can be anything:
– a thread
– a thread-pool
– a process running on another machine
![Page 18: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/18.jpg)
SpyMemcached Example
import java.util.concurrent.{TimeUnit, Future}
import net.spy.memcached.{AddrUtil, MemcachedClient}
val client = new MemcachedClient(
AddrUtil.getAddresses("127.0.0.1:11211")
)
// non-blocking
val f: Future[AnyRef] = client.asyncGet("greeting")
// blocking for the result
val obj = f.get(1, TimeUnit.SECONDS)
if (obj == null) {
println("Greeting not available!")
client.set("greeting", 10000, "Hello World!")
}
else
println(obj)
client.shutdown(1, TimeUnit.SECONDS)
![Page 19: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/19.jpg)
java.util.concurrent.Future
public interface Future<V> {
boolean cancel(boolean);
boolean isCancelled();
boolean isDone();
V get();
V get(long, TimeUnit);
}
Problems?
![Page 20: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/20.jpg)
java.util.concurrent.Future
public interface Future<V> {
boolean cancel(boolean);
boolean isCancelled();
boolean isDone();
V get();
V get(long, TimeUnit);
}
Problems● Blocking● Non-composable
![Page 21: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/21.jpg)
Scala's Futures and Promises
● Designed as a part of Akka● Integrated in Scala's standard library (SIP-14)
![Page 22: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/22.jpg)
scala.concurrent.Future
trait Future[+T] extends Awaitable[T] {
abstract def isCompleted: Boolean
abstract def onComplete[U](func: Try[T] => U)
(implicit ec: ExecutionContext): Unit
abstract def value: Option[Try[T]]
// ...
}
![Page 23: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/23.jpg)
scala.concurrent.Future
import concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Failure, Success}
val f: Future[String] = Future {
"Hello, World!"
}
f.onComplete {
case Success(value) =>
println(value)
case Failure(exception) =>
System.err.println(exception.getMessage)
}
![Page 24: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/24.jpg)
Blocking for the Result
import scala.concurrent.{Await, Future}
import scala.util.{Failure, Success}
import scala.concurrent.duration._
import concurrent.ExecutionContext.Implicits.global
val f: Future[String] = Future {
"Hello, World!"
}
val result = Await.result(f, 10.seconds)
println(result)
![Page 25: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/25.jpg)
scala.concurrent.Future
● onComplete() is too low level● Not composable● Leads to callback hell
![Page 26: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/26.jpg)
Future.foreach()
def squareRoot(x: Double) = Future {
math.sqrt(x)
}
squareRoot(3).foreach { x =>
println(x)
}
![Page 27: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/27.jpg)
Future.foreach()
def squareRoot(x: Double) = Future {
math.sqrt(x)
}
for (x <- squareRoot(3)) {
println(x)
}
![Page 28: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/28.jpg)
Future.map()
def squareRoot(x: Double) = Future {
math.sqrt(x)
}
squareRoot(3).map { x => x + 2 }
![Page 29: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/29.jpg)
Future.map()
def squareRoot(x: Double) = Future {
math.sqrt(x)
}
for (x <- squareRoot(3)) yield x + 2
![Page 30: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/30.jpg)
Future.filter()
import scala.concurrent.{Await, Future}
import concurrent.ExecutionContext.Implicits.global
import concurrent.duration._
val f = Future {
2
}
val r = f.filter(x => x % 2 == 1)
// throws java.util.NoSuchElementException:
// Future.filter predicate is not satisfied
Await.result(r, 1.second)
![Page 31: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/31.jpg)
Future.filter()
import scala.concurrent.{Await, Future}
import concurrent.ExecutionContext.Implicits.global
import concurrent.duration._
val f = Future {
2
}
val r = for (x <- f; if x % 2 == 1) yield x
// throws java.util.NoSuchElementException:
// Future.filter predicate is not satisfied
Await.result(r, 1.second)
![Page 32: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/32.jpg)
On Monads
● It's just a design pattern
![Page 33: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/33.jpg)
On Monads
● It's just a design pattern● A monad is basically a container, or a context● Sometimes, when operating on values, you
want to keep the context
![Page 34: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/34.jpg)
On Monads
● Future[T] is a monadic type● It's a container● It's a context● It allows you to operate on values, even if their
processing finished or not (e.g. within the Future context)
![Page 35: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/35.jpg)
On Monads
● A monadic type M[T] must implement:– a constructor
– map[U](f: T => U): M[U]
– filter(f: T => Boolean): M[T]
– ...
![Page 36: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/36.jpg)
On Monads
● A monadic type M[T] must implement:– a constructor
– map[U](f: T => U): M[U]
– filter(f: T => Boolean): M[T]
– Either of …● flatten()● flatMap[U](f: T => M[U]): M[U]
![Page 37: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/37.jpg)
Future.flatMap()
val client = shade.Memcached(
Configuration("127.0.0.1:11211"),
ActorSystem("default").scheduler,
concurrent.ExecutionContext.Implicits.global
)
val f: Future[String] =
client.get[String]("username") flatMap {
case Some(value) =>
Future.successful("Hello, " + value + "!")
case None =>
client.set("username", "Alex", 30.seconds) map { _ =>
"Hello, Anonymous!"
}
}
![Page 38: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/38.jpg)
Future.flatMap()
val username = client.get[String]("username")
val password = client.get[String]("password")
val userPass: Future[String] =
username.flatMap { user =>
password.map { pass =>
user.getOrElse("anonymous") +
":" +
pass.getOrElse("none")
}
}
![Page 39: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/39.jpg)
Future.flatMap()
val username = client.get[String]("username")
val password = client.get[String]("password")
val userPass: Future[String] =
for (u <- username; p <- password) yield
u.getOrElse("anonymous") +
":" +
p.getOrElse("none")
![Page 40: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/40.jpg)
Future.flatMap()
val user: Future[Option[User]] =
client.get[Option[User]]("user-" + id) flatMap {
// value found in cache
case Some(value) =>
Future.successful(value)
// value not found
case None =>
// fetching from DB
db.fetchUserBy(id) flatMap { value =>
// setting cache
client.set("user-" + id, value, 30.minutes)
.map(_ => value)
}
}
![Page 41: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/41.jpg)
Future.recover()
val client = shade.Memcached(
Configuration("127.0.0.1:11211"),
ActorSystem("default").scheduler,
concurrent.ExecutionContext.Implicits.global
)
client.get[String]("something").recover {
case _: TimeoutException =>
None
}
![Page 42: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/42.jpg)
Future.recoverWith()
googleMaps.search(lat, lon).recoverWith {
case _: APILimitException =>
bingMaps.search(lat, lon)
}
![Page 43: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/43.jpg)
Future.sequence()
val searches = Seq(
googleMaps.search(lat, lon),
bingMaps.search(lat, lon),
geoNames.search(lat, lon)
)
val f: Future[Seq[Option[Location]]] =
Future.sequence(searches)
![Page 44: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/44.jpg)
scala.concurrent.Promise
● The write-side of a Future● An object which can be completed either with a
value or failed with an exception
![Page 45: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/45.jpg)
scala.concurrent.Promise
import concurrent.Promise
val p = Promise[String]()
val f: Future[String] = p.future
// later after processing is done ...
p.success("Hello, World!")
![Page 46: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/46.jpg)
Ning's AsyncHttpClientimport com.ning.http.client._
import concurrent._
class MyAsyncClient(underlying: AsyncHttpClient) {
def fetch(url: String) = {
val promise = Promise[String]()
val handler = new AsyncCompletionHandler[Unit]() {
def onCompleted(resp: Response) {
promise.success(resp.getResponseBodyAsString)
}
def onThrowable(ex: Throwable) {
promise.failure(ex)
}
}
val request = underlying.prepareGet("http://www.google.com/")
request.execute(handler)
promise.future
}
}
![Page 47: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/47.jpg)
Timeout Sampledef withTimeout[T](future: Future, atMost: FiniteDuration) = {
val promise = Promise[T]()
future.onComplete { result =>
promise.tryComplete(result)
}
// schedule the timeout
val scheduler = ActorSystem("default").scheduler
scheduler.scheduleOnce(atMost) {
promise.tryFailure(new TimeoutException)
}
promise.future
}
val value = cacheClient.get[String]("something")
val timed = withTimeout(value, 10.seconds)
timed.recover {
case _: TimeoutException => None
}
![Page 48: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/48.jpg)
Problems
● Debugging● Callback hell still possible
– C# Async is nice
– https://github.com/scala/async
● Too basic for processing streams– Iteratees → uses Future as a building block
![Page 49: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/49.jpg)
Other Alternatives
● Guava● C# Async / System.Threading.Tasks.Task● Q (Javascript)● Twisted Deferred (Python)
![Page 50: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/50.jpg)
Further Learning
● Principles of Reactive Programming (Coursera.org)
● Going Reactive (by Jonas Boner at ScalaDays)● Futures and Promises (docs.scala-lang.org)● Play Framework 2.x
![Page 51: The Future starts with a Promise](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f748bb4c9052a518b4643/html5/thumbnails/51.jpg)
Questions?