Composable Futures
  with Akka 2.0
    by Mike Slinn

     #akkafuture

    at Googleplex
    April 18, 2012
Outline


•   Concurrency 101
•   Akka concurrency options
•   Foundation: java.util.concurrent
•   Definitions
•   Functional programming and concurrency
•   Performance tuning
•   3 demos
Available from
slinnbooks.com
About Mike Slinn

• Principal at Micronautics Research
• Hands-on architect, mentor, trainer
• Interim technical leader for companies in
    transition
•   Recognized in US Federal court as a
    software expert
•   Author of Composable Futures with Akka 2.0
•   Interested in artificial personality
•   Coordinator of BASE and Scala for Startups
Horizontal Scale – More Cores
Threads

• Independent, heap-sharing execution
    contexts
•   Scheduled by the operating system
•   Creation is expensive in Java
•   Pools create additional complexity
•   Cache coherency issues
Multithreading and Callbacks
Standard Thread Pools

• Cached
• Fixed
• Scheduled
• Single
• Single scheduled
• Fork / join (JDK 7 and improved jsr166y)
• Variants with/without daemon threads often
 required
Concurrency Definitions

• Concurrent tasks are stateful, often with
    complex interactions
•   Parallelizable tasks are stateless, do not
    interact, and are composable
java.util.concurrent

• Akka is built on top of
    java.util.concurrent (j.u.c.)
•   Futures are designed to be used with a
    Callable, which returns a result
•   Executors contain factories and utility
    methods for concurrent classes
•   ExecutorService.shutdown()
j.u.c. Primitives

• Callable, Runnable
• Threads, thread pools and Executors
• CompletionService, CountDownLatch,
    concurrent collections, CyclicBarrier,
    Phaser, Semaphone, TimeUnit
•   Primitive Future<T>
j.u.c. Is Too Hard To Use

• Multithreaded programs tend to be buggy
     o Non-determinism caused by concurrent threads
       accessing (shared) mutable state.
• Actors and transactions manage state and
    are therefore not the first solution you should
    consider.
•   To get deterministic processing, avoid
    (shared) mutable state.
Concurrency Hazards

• CPU registers
• L1, L2 and L3 caches
  o L1 cache for each core
  o L2 cache shared by pairs of cores
  o L3 cache shared by all cores
• Processors are different, so a program may
 run fine on one system but fail on another
Cache Line Ping-Pong
Result Array (Scala)
var data = Array(threadCount)
Cache Line Ping-Pong

• 8.5 ms vs. 830 ms (C# code)
• Multicore efficiency: 10%
MESI Protocol

• Each processor cache can be in one of four
    states:
    o   Modified
    o   Exclusive
    o   Shared
    o   Invalid
• When one core writes to main memory, the
    entire cache block is marked invalid
•   Block sizes depend on processor (64 bytes,
    128 bytes, etc.)
Cache Line Ping-Pong

• Manifests even when external state is not
  shared
  o One or more cores repeatedly invalidate caches of
    the other cores, even while accessing isolated state.
  o The other cores must read data from main memory
    instead of their local cache
  o Slows program up to two orders of magnitude.
Cache Line Ping-Pong
1.j.u.c. solution:
@volatile var data = Array(threadCount)
synchronized(data) {
  data(i) = whatever
}

2.Do not access external mutable state from a
   thread
3. Use functional programming techniques
Large, Realtime Guidelines by Prismatic

• Use functional programming to build fine-
    grained, flexible abstractions.
•   Compose these abstractions to express
    problem-specific logic.
•   Prefer lightweight, composable custom
    abstractions rather than monolithic
    frameworks (e.g., Hadoop).
Functional-Style Pipelines

• *nix pipes (linear)

• Scala parallel collections & Akka composable
  futures (parallel)
Better Concurrency Options

• Ordered by increasing complexity & overhead
   o   j.u.c.
   o   Scala parallel collections
   o   Akka futures* (Java & Scala)
   o   Akka/Scala dataflow*
   o   Akka actors (Java & Scala)
• You can mix & match the above
* Covered in my book:
  “Composable Futures with Akka 2.0”
 Covered in my April 23 InfoQ article.
Scala Parallel Collections

• Very easy to use
• Not configurable
• Block
• Composable
• Easy to reason with
• Benefits from ongoing improvements to
 ForkJoinPool
  o (Scala uses jsr166y)
Akka and j.u.c.
Akka Dispatchers and j.u.c.
Akka/Scala Dataflow*

• Callable from Scala only
• Has peculiar operators
• Easy to reason with
• Designed for shared mutable state
• Dataflow blocks are composable
• Good for coordination of asynchronous
    activities
•   Good for consolidating multiple sources of
    data
Akka Actors

• Callable from Java & Scala
• Over-hyped (remember EJB 2?)
• Most complex option
• Distributed concurrency: can scale beyond
    one motherboard
•   Not composable
•   Can be difficult or impossible to prove correct
•   This should be your last option to consider
Akka Futures

• Callable from Java & Scala
• More flexible than Scala parallel collections
• Much less complex than Akka actors
• Composable
• Easy to reason with
• Payloads (Callables) should not have side
    effects
•   Should not be used with shared mutable
    state
What is a Future?

• Holder for a result that will become available
    at a later time.
•   Each future is backed by a thread.
•   If the computation fails, the future can also
    hold the resulting Throwable.
•   Write-once (immutable)
•   Akka and Twitter futures are composable and
    transformable (j.u.c. futures are not)
Akka & Twitter Futures

• Manage concurrency
• Higher-level than j.u.c. primitives
• Immutable
• Inexpensive
• Can be preset to a value or exception when
    created.
•   Blocking and non-blocking operations
    supported
Composable Futures

• Operations on a future or a collection of
    futures can be chained together without
    blocking
•   Transformations such as map and flatMap
    can be applied to a single future
•   Collections of futures can be manipulated
Akka Future Operations

• flatMap, map
• flow
• foreach, zip, firstCompletedOf, fold,
    reduce, sequence, traverse
•   andThen, fallbackTo, onComplete,
    onFailure, onSuccess, recover
Composable Futures Rock

• Twitter uses composable (Twitter) futures, no
    actors
•   KloutAPI uses Play Framework
    AsyncResults, fed by Akka futures. Load
    dropped in half
ExecutorBenchmark
Statistical Nature




  Large standard deviation; values are not tightly clustered around the
     median; results vary a lot each time a measurement is taken.




Small standard deviation; values are tightly clustered around the median;
      results do not vary much each time a measurement is taken.
Standard Deviation

• Measurements tend to lie within one standard
 deviations either side of the mean
Configure Thread Pools at Deployment


• Number and type of processors and other
    hardware affects behavior
•   Interaction with other thread pools
•   Akka supports configuration files and
    configuration strings for setting up thread
    pools
Demo Time!

• Simple futures
• Try / catch / finally constructs
• flatMap
flatMap Demo

• Combination of Future.map() and
    List.flatten()
•   Walks through a list and generates a second
    list by flattening each item in the first list
•   Will not evaluate the passed-in functor if the
    future failed
•   This demo implements the pseudo-code that
    Marius Eriksen of Twitter showed for
    flatMap last week at the Bay Area Scala
    Enthusiasts meetup
flatMap Demo

1.Look up a token; return the user ID if
   successful, otherwise fail.
2. Use the user ID to obtain a user information
   if step 1 did not fail.
Code Summary

val userF: Future[User] =
    Future(authenticate(token))
      flatMap(id => getUser(id))
userF onComplete {
  case Right(value: User) =>
    println(value)
  case Left(exception) =>
    println(exception.getMessage)
}
Thank you!


            Mike Slinn
         slinnbooks.com

Composable Futures with Akka 2.0

  • 1.
    Composable Futures with Akka 2.0 by Mike Slinn #akkafuture at Googleplex April 18, 2012
  • 2.
    Outline • Concurrency 101 • Akka concurrency options • Foundation: java.util.concurrent • Definitions • Functional programming and concurrency • Performance tuning • 3 demos
  • 3.
  • 4.
    About Mike Slinn •Principal at Micronautics Research • Hands-on architect, mentor, trainer • Interim technical leader for companies in transition • Recognized in US Federal court as a software expert • Author of Composable Futures with Akka 2.0 • Interested in artificial personality • Coordinator of BASE and Scala for Startups
  • 5.
  • 6.
    Threads • Independent, heap-sharingexecution contexts • Scheduled by the operating system • Creation is expensive in Java • Pools create additional complexity • Cache coherency issues
  • 7.
  • 8.
    Standard Thread Pools •Cached • Fixed • Scheduled • Single • Single scheduled • Fork / join (JDK 7 and improved jsr166y) • Variants with/without daemon threads often required
  • 9.
    Concurrency Definitions • Concurrenttasks are stateful, often with complex interactions • Parallelizable tasks are stateless, do not interact, and are composable
  • 10.
    java.util.concurrent • Akka isbuilt on top of java.util.concurrent (j.u.c.) • Futures are designed to be used with a Callable, which returns a result • Executors contain factories and utility methods for concurrent classes • ExecutorService.shutdown()
  • 11.
    j.u.c. Primitives • Callable,Runnable • Threads, thread pools and Executors • CompletionService, CountDownLatch, concurrent collections, CyclicBarrier, Phaser, Semaphone, TimeUnit • Primitive Future<T>
  • 12.
    j.u.c. Is TooHard To Use • Multithreaded programs tend to be buggy o Non-determinism caused by concurrent threads accessing (shared) mutable state. • Actors and transactions manage state and are therefore not the first solution you should consider. • To get deterministic processing, avoid (shared) mutable state.
  • 13.
    Concurrency Hazards • CPUregisters • L1, L2 and L3 caches o L1 cache for each core o L2 cache shared by pairs of cores o L3 cache shared by all cores • Processors are different, so a program may run fine on one system but fail on another
  • 14.
    Cache Line Ping-Pong ResultArray (Scala) var data = Array(threadCount)
  • 15.
    Cache Line Ping-Pong •8.5 ms vs. 830 ms (C# code) • Multicore efficiency: 10%
  • 16.
    MESI Protocol • Eachprocessor cache can be in one of four states: o Modified o Exclusive o Shared o Invalid • When one core writes to main memory, the entire cache block is marked invalid • Block sizes depend on processor (64 bytes, 128 bytes, etc.)
  • 17.
    Cache Line Ping-Pong •Manifests even when external state is not shared o One or more cores repeatedly invalidate caches of the other cores, even while accessing isolated state. o The other cores must read data from main memory instead of their local cache o Slows program up to two orders of magnitude.
  • 18.
    Cache Line Ping-Pong 1.j.u.c.solution: @volatile var data = Array(threadCount) synchronized(data) { data(i) = whatever } 2.Do not access external mutable state from a thread 3. Use functional programming techniques
  • 19.
    Large, Realtime Guidelinesby Prismatic • Use functional programming to build fine- grained, flexible abstractions. • Compose these abstractions to express problem-specific logic. • Prefer lightweight, composable custom abstractions rather than monolithic frameworks (e.g., Hadoop).
  • 20.
    Functional-Style Pipelines • *nixpipes (linear) • Scala parallel collections & Akka composable futures (parallel)
  • 21.
    Better Concurrency Options •Ordered by increasing complexity & overhead o j.u.c. o Scala parallel collections o Akka futures* (Java & Scala) o Akka/Scala dataflow* o Akka actors (Java & Scala) • You can mix & match the above * Covered in my book: “Composable Futures with Akka 2.0”  Covered in my April 23 InfoQ article.
  • 22.
    Scala Parallel Collections •Very easy to use • Not configurable • Block • Composable • Easy to reason with • Benefits from ongoing improvements to ForkJoinPool o (Scala uses jsr166y)
  • 23.
  • 24.
  • 25.
    Akka/Scala Dataflow* • Callablefrom Scala only • Has peculiar operators • Easy to reason with • Designed for shared mutable state • Dataflow blocks are composable • Good for coordination of asynchronous activities • Good for consolidating multiple sources of data
  • 26.
    Akka Actors • Callablefrom Java & Scala • Over-hyped (remember EJB 2?) • Most complex option • Distributed concurrency: can scale beyond one motherboard • Not composable • Can be difficult or impossible to prove correct • This should be your last option to consider
  • 27.
    Akka Futures • Callablefrom Java & Scala • More flexible than Scala parallel collections • Much less complex than Akka actors • Composable • Easy to reason with • Payloads (Callables) should not have side effects • Should not be used with shared mutable state
  • 28.
    What is aFuture? • Holder for a result that will become available at a later time. • Each future is backed by a thread. • If the computation fails, the future can also hold the resulting Throwable. • Write-once (immutable) • Akka and Twitter futures are composable and transformable (j.u.c. futures are not)
  • 29.
    Akka & TwitterFutures • Manage concurrency • Higher-level than j.u.c. primitives • Immutable • Inexpensive • Can be preset to a value or exception when created. • Blocking and non-blocking operations supported
  • 30.
    Composable Futures • Operationson a future or a collection of futures can be chained together without blocking • Transformations such as map and flatMap can be applied to a single future • Collections of futures can be manipulated
  • 31.
    Akka Future Operations •flatMap, map • flow • foreach, zip, firstCompletedOf, fold, reduce, sequence, traverse • andThen, fallbackTo, onComplete, onFailure, onSuccess, recover
  • 32.
    Composable Futures Rock •Twitter uses composable (Twitter) futures, no actors • KloutAPI uses Play Framework AsyncResults, fed by Akka futures. Load dropped in half
  • 33.
  • 34.
    Statistical Nature Large standard deviation; values are not tightly clustered around the median; results vary a lot each time a measurement is taken. Small standard deviation; values are tightly clustered around the median; results do not vary much each time a measurement is taken.
  • 35.
    Standard Deviation • Measurementstend to lie within one standard deviations either side of the mean
  • 36.
    Configure Thread Poolsat Deployment • Number and type of processors and other hardware affects behavior • Interaction with other thread pools • Akka supports configuration files and configuration strings for setting up thread pools
  • 37.
    Demo Time! • Simplefutures • Try / catch / finally constructs • flatMap
  • 38.
    flatMap Demo • Combinationof Future.map() and List.flatten() • Walks through a list and generates a second list by flattening each item in the first list • Will not evaluate the passed-in functor if the future failed • This demo implements the pseudo-code that Marius Eriksen of Twitter showed for flatMap last week at the Bay Area Scala Enthusiasts meetup
  • 39.
    flatMap Demo 1.Look upa token; return the user ID if successful, otherwise fail. 2. Use the user ID to obtain a user information if step 1 did not fail.
  • 40.
    Code Summary val userF:Future[User] = Future(authenticate(token)) flatMap(id => getUser(id)) userF onComplete { case Right(value: User) => println(value) case Left(exception) => println(exception.getMessage) }
  • 41.
    Thank you! Mike Slinn slinnbooks.com

Editor's Notes

  • #5 http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.htmlhttp://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html
  • #6 http://simplygenius.net/Article/FalseSharinghttp://en.wikipedia.org/wiki/MESI_protocolAMD Opteron and Intel i7 caches are quite different, for example
  • #14 Scala futures?