Upload
johan-andren
View
1.408
Download
1
Tags:
Embed Size (px)
DESCRIPTION
Slides from my talk about Async with Play framework Scala and Java from the PingConf in Budapest january 2014
Citation preview
AsyncReact instead of waiting for better times
Johan Andrén [email protected] @apnylle
Who am I?Java/JVM - Last 8 yearsScala & Play - Last 2 years
@apnylleJohan Andrén
ConsultantHome
You are here now
Most modern web frameworks
Request
Response
t1
t1
Thread pool
What does that thread spend most of its time doing?
Hint:
Wait
resource
Request
Response
Blocked
your logic
your logic
Request
Response
Why is this a problem?
20 db connections 200 threads
200 concurrent db-using reqs
1 req for non db url
Why is this a problem? (also)
• Cloud providers - thread cap/node
• Streaming data over http
• many threads - overhead(s)
How would we like it to work?
No logic executing: no thread taken
resource
We´ll call you
Our logic
Our logic ResourceAsync API
Don´t call us
QWe can’t really do more cpu-bound work than the number of cores simultaneously
So If no thread ever blocks
we don’t really need:
more threads than cores
What do we need?
• Ways to do callbacks
• Framework support
but doesn’t callbacks lead to...
1 GMaps.geocode({! 2 address: fromAddress,! 3 callback: function( results, status ) {! 4 if ( status == "OK" ) {! 5 fromLatLng = results[0].geometry.location;! 6 GMaps.geocode({! 7 address: toAddress,! 8 callback: function( results, status ) {! 9 if ( status == "OK" ) {!10 toLatLng = results[0].geometry.location;!11 map.getRoutes({!12 origin: [ fromLatLng.lat(), fromLatLng.lng() ],!13 destination: [ toLatLng.lat(), toLatLng.lng() ],!14 travelMode: "driving",!15 unitSystem: "imperial",!16 callback: function( e ){!17 console.log("ANNNND FINALLY here's the directions..." );!18 // do something with e!19 }!20 });!21 }!22 }!23 });!24 }!25 }!26 });!
”Callback Hell”?
Not with better abstractions!
25 }!26 });
• Futures / Promises
• Actors
• Iteratees
IntermissionSHARK!
SHARK! SHARK!
Futures”I promise that I will give you a Kitten, when you are old enough to take care of
it””When I (in the future) Get a kitten I will play with it
all day”
Promise[Kitten]complete(kitten)failure(Reason)
onComplete(play) onFailure(cry)
Side effect!!!Future[Kitten]
Transforming the future
Future[A] Future[B]
map(f: A => B)a b
f(a)
If the future isn’t that bright
Future[A] Future[B]
Map
Example - the play web client
: Future[SimpleResult]
Example - the play web client
Chaining futures
map(A => B)
Future[B]
map(B => C)
Future[C]
Future[A]WS Response => model Object
model Object => HTML
Even more flexibility
Future[A] Future[B]
flatMap(A => Future[B])
List[Future[A]]
Future.sequenceFuture[List[A]]
Even more even more flexibility
List[Future[A]]
Future.firstCompletedOfFuture[A]
List[Future[A]]Future.fold
Future[B]
But, wait a minute, where is it executed?
• Scala
• Implicit execution context required
• map(A => B)(implicit ctx)
• Java • Default
• map(A => B, CTX)
ExecutionContext
Runnable:s
ThreadpoolT1 T2 Tn
So, when should I use futures?
• When talking to other services (ws, db, etc)
• For parallell work
• Simple one off background stuff
• ?
Actors
Inbox
Behaviour
State
Example - actors and the ask pattern
Example - actors and the ask pattern
Example - actors and the ask pattern
Request 1
Request 2
Request 3
Response 1
Response 2
Response 3
Thread 1
Thread 2
Thread 3
Shared Mutable
Resource
Threads blocked!
Request 1
Request 2
Request 3
Response 1
Response 2
Response 3
Actor with
state
So, when should I use actors?
• When you need state
• Streaming data into or out of play
• As a base for event driven apps
• Background work
• ?
IterateesSmall, simple and witty illustration of Iteratees
(best case: including cats)
Traditional imperative Java IO
Thread blocked!
How would we want it to work?
• react on each chunk
• build something out of those chunks
• bail out early
Let’s model that:
Input
El(element) EOF Empty
Let’s model that:
Step
Cont(Input =>Step) Done(result) Error(why)
What to do with next input
Iteratee
Enumerator
Let’s model that:
Cont(Input =>Step)EL(”kittenA”)
EL(”kittenB”)
EOF
Cont(Input =>Step)
Cont(Input =>Step)
Done(List(”kittenA”,”kittenB”))
(Starting state)
Let’s model that:
Enumerator[E] Iteratee[E, R]
E: The type of the chunks
Even moar:
Enumerator[A] Iteratee[B, R]
Enumeratee[A, B]
Example
Example
Example
So, when should I use Iteratees?
• When you need to stream data
• You probably already do! (BodyParsers)
• ?
Async: What to look out for
• IO • Enumerator.from{File|Stream}
• Really heavy/long computations
• Blocking by mistake
• JDBC
How to make sync async• Futures
• Important: using a separate bounded ExecutionContext
• scala.concurrent.blocking
• Actors
Async: Drawbacks
• MMMM - (Monad-Mixing Makes Mess)
• Shorter stacks - stacktraces not that helpful :(
• ThreadLocal
Is there a case where async shouldn’t be used?
Possibly: Few (and predictable) concurrent connections and a need of as
good response times as possible
Entirely cpu bound apps
Final words
Play makes async easy (and fun)both with Java and Scala!
Also: Know your abstractions!
Johan Andrén [email protected] @apnylle
K Thx Bye!
Qs?
github.com/johanandren/ping-conf-scala github.com/johanandren/ping-conf-java