async - react, don't wait - pingconf
DESCRIPTION
Slides from my talk about Async with Play framework Scala and Java from the PingConf in Budapest january 2014TRANSCRIPT
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