"Do not block threads!" a blessing in disguise or a curse? - - PowerPoint PPT Presentation

do not block threads
SMART_READER_LITE
LIVE PREVIEW

"Do not block threads!" a blessing in disguise or a curse? - - PowerPoint PPT Presentation

"Do not block threads!" a blessing in disguise or a curse? @sadache prismic.io co-founder, Play framework co-creator Modern Applications Spend a considerable time talking to internet Internet means latency How does your


slide-1
SLIDE 1

"Do not block threads!"

a blessing in disguise or a curse?

slide-2
SLIDE 2

@sadache

prismic.io co-founder, Play framework co-creator

slide-3
SLIDE 3

Modern Applications

  • Spend a considerable time talking to internet
  • Internet means latency
  • How does your runtime integrate this latency?
slide-4
SLIDE 4
slide-5
SLIDE 5

A Typical Request

App

l a t e n c y

Service

slide-6
SLIDE 6

We should not waste scarce resources

while waiting for work to be done on other machines

  • Memory, CPU, …
  • Threads/processes?
  • lightweight (millions on a single machines)
  • heavyweight? …
slide-7
SLIDE 7
slide-8
SLIDE 8
slide-9
SLIDE 9

JVM and co

  • Threads are scarce resources (or are they? )
  • We should not hold to threads while doing IO (or

internet call)

  • “Do not block threads!”
slide-10
SLIDE 10
slide-11
SLIDE 11

Copy that! what CAN I do?

slide-12
SLIDE 12

Do not block threads!

  • Then what should I do?
  • Non blocking IO and Callbacks
  • ws.get(url, { result =>


println(result)
 })

  • What happens if I want to do another call after?
  • Callback hell!
slide-13
SLIDE 13
slide-14
SLIDE 14

Futures! (Tasks, Promises, …)

  • Future[T] represents a result of type T that we are

eventually going to get (at the completion of the Future)

  • Doesn’t block the thread
  • But how can I get the T inside?
  • // blocking the current thread until completion of the future?


Result.await(future)

slide-15
SLIDE 15

Examples of Future composition

val eventuallyTweet: Future[String] = … val et: Future[Tweet] = eventuallyTweet.map(t => praseTweet(t))

  • val tweets: Seq[Future[Tweet]] = …

val ts: Future[Seq[Tweet]] = Future.sequence(tweets)

slide-16
SLIDE 16

Future composition

slide-17
SLIDE 17

Future composition

slide-18
SLIDE 18

Future composition

slide-19
SLIDE 19

Some syntax sugar

// for comprehensions for { t <- getTweet(id) k <- getKloutScore(t.user) } yield (t,k)

slide-20
SLIDE 20

Futures are elegant

  • all, any, monads, applicatives, functors
  • do all the scheduling and synchronisation behind

the scenes

slide-21
SLIDE 21

Future is not satisfactory

slide-22
SLIDE 22

Futures are not completely satisfactory

  • Manage execution on completion (who is

responsible of executing the code?)

  • Additional logic complexity (adding one level of

indirection)

  • Has a big impact on your program (refactorings)
  • Ceremony, or am I doing the compiler/runtime work?
  • Stacktrace gone!
slide-23
SLIDE 23

Who runs this code?

val eventuallyTweet: Future[String] = … val et: Future[Tweet] = eventuallyTweet.map(t => praseTweet(t))

slide-24
SLIDE 24

Futures are not completely satisfactory

  • Manage execution on completion (who is

responsible of executing the code?)

  • Additional logic complexity (adding one level of

indirection)

  • Has a big impact on your program (refactorings)
  • Ceremony, or am I doing the compiler/runtime work?
  • Stacktrace gone!
slide-25
SLIDE 25

Scala’s solution to execution management (on completion)

  • Execution Context
  • def map[S](f: (T) ⇒ S)(implicit executor: ExecutionContext): Future[S]
  • Just import the appropriate EC
  • Very tough to answer the question (developers tend to

chose the default EC, can lead to contentions)

  • import scala.concurrent.ExecutionContext.global
  • Contention?
slide-26
SLIDE 26

Futures are poor man’s lightweight threads

  • You might be stuck with them if you’re stuck with

heavyweight threads…

  • Scala async
  • Why not an async for the whole program?
slide-27
SLIDE 27

Futures are poor man’s lightweight threads

val future = async {

  • val f1 = async { ...; true }
  • val f2 = async { ...; 42 }
  • if (await(f1)) await(f2) else 0
  • }
slide-28
SLIDE 28

Futures are poor man’s lightweight threads

  • You might be stuck with them if you’re stuck with

heavyweight threads…

  • Scala async
  • Why not an async for the whole program?
slide-29
SLIDE 29

Inversion of control (Reactive)

  • Future but for multiple values (streams)
  • Just give us a Function and we call you each time

there is something to do

  • Mouse.onClick { event => println(event) }
slide-30
SLIDE 30

Inversion of control (Reactive)

  • What about maintaining state across calls
  • Composability and tools
  • Iteratees, RX, Streams, Pipes, Conduits, … etc
slide-31
SLIDE 31

Iteratees

<a quick introduction>

slide-32
SLIDE 32

Iteratees

  • What about maintaining state between calls
  • Composability and tools
  • Iteratees, RX, Streams, Pipes, Conduits, … etc
slide-33
SLIDE 33

Iteratees

trait Step case class Cont( f:E => Step) extends Step case class Done extends Step

slide-34
SLIDE 34

Iteratees

trait Step[E,R] case class Cont[E,R]( f:E => Step[E,R]) extends Step[E,R] case class Done(r: R) extends Step[Nothing, R]

slide-35
SLIDE 35

Iteratees

// A simple, manually written, Iteratee val step = Cont[Int, Int]( e => Done(e)) //feeding 1 step match { case Cont(callback) => callback(1) case Done(r) => // shouldn’t happen }

slide-36
SLIDE 36

Counting characters

// An Iteratee that counts characters def charCounter(count:Int = 0): Step[String, Int] = Cont[String, Int]{ case Chunk(e) => charCounter(count + e.length) case EOF => Done(count) }

slide-37
SLIDE 37

Iteratees

trait Input[E] case class Chunk[E](e: E) case object EOF extends Input[Nothing]

  • trait Step[E,R]

case class Cont[E,R]( f:E => Step[E,R]) extends Step[E,R] case class Done(r: R) extends Step[Nothing, R]

slide-38
SLIDE 38

Counting characters

slide-39
SLIDE 39

Counting characters

// An Iteratee that counts characters def charCounter(count:Int = 0): Step[String, Int] = Cont[String, Int]{ case Chunk(e) => step(count + e.length) case EOF => Done(count) }

slide-40
SLIDE 40

Same principle

  • count, getChunks, println, sum, max, min, etc
  • progressive stream fold (fancy fold)
  • Iteratee is the reactive stream consumer
slide-41
SLIDE 41

Enumerators

  • Enumerator[E] is the source, it iteratively checks on the Step

state and feeds input of E if necessary (Cont state)

  • Enumerators can generate, or retrieve, elements from anything
  • Files, sockets, lists, queues, NIO
  • Helper constructors to build different Enumerators
slide-42
SLIDE 42

Enumeratees

  • Adapters
  • Apply to Iteratees and/or Enumerators to adapt their input
  • Create new behaviour
  • map, filter, buffer, drop, group, … etc
slide-43
SLIDE 43

Iteratees

</ a quick introduction>

slide-44
SLIDE 44

Iteratees

Inversion of controls: Enumerators chose when to call the Iteratees continuation They chose on which Thread to run continuation What if an Iteratee (or Enumeratee) decided to do a network call? Block the thread waiting for a response?

slide-45
SLIDE 45

Counting characters

// An Iteratee that counts characters def sumScores(count:Int = 0): Step[String, Int] = Cont[String, Int]{ case Chunk(e) => 
 
 val eventuallyScore: Future[Int] = webcalls.getScore(e)
 
 step(count + Result.await(eventuallyScore)) // seriously??? case EOF => Done(count) }

slide-46
SLIDE 46

Reactive all the way

// An Iteratee that counts characters def sumScores(count:Int = 0): Step[String, Int] = Cont[String, Int]{ case Chunk(e) => 
 
 val eventuallyScore: Future[Int] = webcalls.getScore(e)
 
 step(count + Result.await(eventuallyScore)) // seriously??? case EOF => Done(count) }

slide-47
SLIDE 47

Iteratees

trait Step[E,R] case class Cont[E,R]( f:E => Step[E,R]) extends Step[E,R] case class Done(r: R) extends Step[Nothing, R]

slide-48
SLIDE 48

Iteratees

trait Step[E,R] case class Cont[E,R]( f:E => Future[Step[E,R]]) extends Step[E,R] case class Done(r: R) extends Step[Nothing, R]

slide-49
SLIDE 49

Reactive all the way

// An Iteratee that counts characters def sumScores(count:Int = 0): Step[String, Int] = Cont[String, Int]{ case Chunk(e) => 
 
 val eventuallyScore: Future[Int] = webcalls.getScore(e)
 
 eventuallyScore.map( s => step(count + s)) case EOF => Future.successful(Done(count)) }

slide-50
SLIDE 50

Seamless integration between Futures and Iteratees

Seq[Future[E]] is an Enumerator[E] Iteratees can integrate any Future returning call Back-pressure for free

slide-51
SLIDE 51

Suffer from the same drawbacks of Futures

  • Manage execution on completion (who is

responsible of executing the code?)

  • Everything becomes a Future
  • Stacktrace gone!
slide-52
SLIDE 52

Elegant, help manage complexity of asynchronous multiple messages

Composable Builders and helpers Modular

slide-53
SLIDE 53

Recap

  • Stuck with heavyweight threads?
  • NIO and Callback hell
  • Futures
  • Composable Futures
  • Iteratees and co
  • Developer suffering from what the runtime/compiler couldn’t

provide

slide-54
SLIDE 54

Asynchronous Programming

is the price you pay, know what you’re paying for

slide-55
SLIDE 55

The price is your productivity

slide-56
SLIDE 56

Asynchronous Programming

calculate your cost effectiveness

slide-57
SLIDE 57

Questions