Async vs Futures

32
Philipp Haller @philippkhaller Futures and Async: When to Use Which?

Transcript of Async vs Futures

Page 1: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 1/31

Philipp Haller@philippkhaller

Futures and Async:When to Use Which?

Page 2: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 2/31

Page 3: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 3/31

Overview

• A brief guide to the Future of Scala

• What is a Promise good for?

• What is Async?

Guidelines on when to use which

Page 4: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 4/31

FutureCreation

object Future {

// [use case] 

def apply[T](body: => T): Future[T]

// .. }

 Example

val fstGoodDeal =

Future {

usedCars.find(car => isGoodDeal(car))

}

Page 5: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 5/31

Future

trait Future[+T] extends Awaitable[T] {

// [use case] 

def map[S](f: T => S): Future[S]

// [use case] def flatMap[S](f: T => Future[S]): Future[S]

// .. 

}

Type

 Example

val fstGoodDeal: Future[Option[Car]] = ..

val fstPrice: Future[Int] =

fstGoodDeal.map(opt => opt.get.price)

Page 6: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 6/31

Future Pipelining

val lowestPrice: Future[Int] =

fstPrice.flatMap { p1 =>

sndPrice.map { p2 =>

math.min(p1, p2) }

}

Page 7: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 7/31

Collections of Futures

val goodDeals: List[Future[Option[Car]]] = ..

val bestDeal: Future[Option[Car]] =

Future.sequence(goodDeals).map(

deals => deals.sorted.head

)

Page 8: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 8/31

Promise Main purpose: create futures for non-lexically-scoped asynchronous code

def after[T](delay: Long, value: T): Future[T]

 Example

Function for creating a Future that is completed

with value after delay  milliseconds

Page 9: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 9/31

“after”, Version 1

def after1[T](delay: Long, value: T) =

Future {

Thread.sleep(delay)

value

}

Page 10: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 10/31

“after”, Version 1

assert(Runtime.getRuntime()

.availableProcessors() == 8)

for (_ <- 1 to 8) yield

after1(1000, true)

val later = after1(1000, true)

 How does it behave?

Quiz: when is “later” completed?

Answer: after either ~1 s or ~2 s (most often)

Page 11: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 11/31

Promise

object Promise {

def apply[T](): Promise[T]

}

trait Promise[T] {

def success(value: T): this.type

def failure(cause: Throwable): this.type

def future: Future[T]}

Page 12: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 12/31

“after”, Version 2

def after2[T](delay: Long, value: T) = {

val promise = Promise[T]()

timer.schedule(new TimerTask {def run(): Unit = promise.success(value)

}, delay)

promise.future

}

 Much better behaved! 

Page 13: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 13/31

Managing BlockingWhat if there is no asynchronous variant of arequired API?

import scala.concurrent.blocking

def after3[T](delay: Long, value: T) =

Future {

blocking { Thread.sleep(delay) }

value}

Page 14: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 14/31

ManagedBlocker

public static interface ManagedBlocker {

boolean block() throws InterruptedException;boolean isReleasable();

}

Page 15: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 15/31

What is Async?

• New Scala module

• "org.scala-lang.modules" %% "scala-async" 

• Purpose: simplify non-blocking concurrency  

• SIP-22 (June 2013)

• Releases for Scala 2.10 and 2.11

Page 16: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 16/31

What Async Provides

• Future and Promise provide types and

operations for managing data flow  

• There is very little support for control flow

• For-comprehensions, ..?

• Async complements Future and Promise with

new constructs to manage control flow 

Page 17: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 17/31

Programming Model

Basis: suspendible computations 

• async { … } — delimit suspendible computation

• await(obj) — suspend computation until an

event is signaled to obj

Example: Future

Page 18: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 18/31

Async

object Async {

// [use case] 

def async[T](body: => T): Future[T]

def await[T](future: Future[T]): T

}

Page 19: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 19/31

Example

val fstGoodDeal: Future[Option[Car]] = ..

val sndGoodDeal: Future[Option[Car]] = ..

val goodCar = async {

val car1 = await(fstGoodDeal).get

val car2 = await(sndGoodDeal).get

if (car1.price < car2.price) car1

else car2

}

Page 20: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 20/31

Guidelines

Page 21: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 21/31

Item #1Use async/await instead of (deeply-)nestedmap/flapMap calls

val goodCar = fstGoodDeal.flatMap { fstDeal =>

val car1 = fstDeal.getsndGoodDeal.map { sndDeal =>

val car2 = sndDeal.get

if (car1.price < car2.price) car1

else car2

}}

BAD!

Page 22: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 22/31

Item #1Use async/await instead of (deeply-)nestedmap/flapMap calls

val goodCar = async {

val car1 = await(fstGoodDeal).getval car2 = await(sndGoodDeal).get

if (car1.price < car2.price) car1

else car2

}

Page 23: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 23/31

Item #2Use async/await instead of complex for-comprehensions

def nameOfMonth(num: Int): Future[String] = ...

val date = ”””(\d+)/(\d+)”””.r

for { doyResponse <- futureDOY

dayOfYear = doyResponse.body

response <- dayOfYear match {

case date(month, day) =>

for (name <- nameOfMonth(month.toInt))yield Ok(s”It’s $name!”)

case _ =>

Future.successful(NotFound(“Not a...”))

}

} yield response

BAD!

Page 24: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 24/31

Item #2Use async/await instead of complex for-comprehensions

def nameOfMonth(num: Int): Future[String] = ...

val date = ”””(\d+)/(\d+)”””.r

async {

await(futureDOY).body match {

case date(month, day) =>

Ok(s”It’s ${await(nameOfMonth(month.toInt))}!”)

case _ =>NotFound(“Not a date, mate!”)

}

}

Page 25: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 25/31

Item #3Use combinators for collections of futures insteadof async/await and imperative while-loops

val futures = ..

async {

var results = List[T]()

var i = 0

while (i < futures.size) {

results = results :+ await(futures(i))

i += 1

}

results

}

BAD!

Page 26: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 26/31

Item #3Use combinators for collections of futures insteadof async/await and imperative while-loops

val futures = ..

Future.sequence(futures)

Page 27: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 27/31

Item #4

 Do not accidentally sequentialize futures

for {

x <- Future { .. }

y <- Future { .. }} yield {

..

}

BAD!

Page 28: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 28/31

Item #4

 Do not accidentally sequentialize futures

futX = Future { .. }

futY = Future { .. }

async {

val x = await(futX)

val y = await(futY)

..

}

Page 29: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 29/31

Item #5

Use Async to improve performance 

• Async reduces closure allocations compared

to code using higher-order functions like map,flatMap, etc.

• Async reduces boxing  of primitive values in

some cases

Page 30: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 30/31

Item #6Use Async because of future extensions

Since Async is a macro library, we will be able to

do useful rewritings in the future:

•  Automatic parallelization of Future-

returning calls if no dependencies

• Optionally configure await calls to beblocking to maintain intact thread stack

Page 31: Async vs Futures

8/11/2019 Async vs Futures

http://slidepdf.com/reader/full/async-vs-futures 31/31

Conclusion

• Focus on Future, not Promise

Use Promise only when necessary

• Async is there to simplify Future-based code

• Async is production-ready