Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Asynchronous programming and Scala

Avatar for Ayushi Ayushi
April 22, 2020

Asynchronous programming and Scala

The intent of this presentation is to explain what is asynchronous programming, how is it relevant in building concurrent services & distributed systems. Some intuition is provided about Asynchronous programming using Scala - mostly Futures, some common misconceptions and pitfalls to avoid while programming async. Most of the instruction is using coding examples.

Avatar for Ayushi

Ayushi

April 22, 2020
Tweet

More Decks by Ayushi

Other Decks in Programming

Transcript

  1. Index 1. What is asynchronous programming? 2. Why talk about

    it? 3. Use cases 4. Asynchronous programming in Scala 5. Futures & Promises 6. Futures drawbacks 7. Common misconceptions 8. Pitfalls while programming async
  2. What is it? • Asynchronous programming is a means of

    parallel programming in which a unit of work runs separately from the main application thread and notifies the calling thread of its completion, failure or progress. • Not necessarily - performance improvement in terms of time. Instead - Improves throughput.
  3. Example (Subtle differences) X asks Y: do you have a

    book named “Learning Scala”? 1) blocking: before Y answers X, X keeps waiting there for the answer. Now X (one module) is blocking. X and Y are two threads or two processes or one thread or one process? we DON'T know. 2) non-blocking: before Y answers X, X just leaves there and do other things. X may come back every two minutes to check if Y has finished its job? Or X won't come back until Y calls him? We don't know. We only know that X can do other things before Y finishes its job. Here X (one module) is non-blocking. X and Y are two threads or two processes or one process? we DON'T know. BUT we are sure that X and Y couldn't be one thread. 3) synchronous: before Y answers X, X keeps waiting there for the answer. It means that X can't continue until Y finishes its job. Now we say: X and Y (two modules) are synchronous. X and Y are two threads or two processes or one thread or one process? we DON'T know. 4) asynchronous: before Y answers X, X leaves there and X can do other jobs. X won't come back until Y calls him. Now we say: X and Y (two modules) are asynchronous. X and Y are two threads or two processes or one process? we DON'T know. BUT we are sure that X and Y couldn't be one thread.
  4. Why talk about it? • Parallelisation/ Concurrency (~Distributed) • Scalability

    - Horizontal vs Vertical* • Availability • Consistency • Eventual consistency, Linearizability, Causal consistency, Sequential consistency. • Functional programming - Why Scala/FP for async? • Computational bound tasks vs IO bound tasks
  5. Use cases • UI for a webapp: increases responsiveness •

    Backend micro-services (making network calls) : better vertical scalability/ better throughput • DB actions • val result: User = DB.Users.byId(42) • val result: Future[User] = Future{ DB.Users.byId(42)}
  6. Async in scala 1. Futures/Promises - Scala API 2. Actors

    - Akka actor system 3. Streams - RxScala, Akka Streams 4. Libs & 3rd party frameworks - Scala Async, Play framework, Monix, Scalaz- zio, Cats-effect IO
  7. Execution Context 1. Similar to Java Executor. 2. Intent: lexically

    scope code execution. 3. Defines a thread pool which decides where the callback will be executed. 4. To separate business logic from execution logic. 5. scala.concurrent provides ExecutionContext.global backed by Fork/Join pool. implicit val ec = scala.concurrent.ExecutionContext.global def task1(param: String)(implicit ec: ExecutionContext) 6. Global EC defaults the # of threads to # of processors.
  8. Futures 1. A placeholder object for a value that may

    become available at some point. 2. Immutable 3. Eager evaluation 4. Computation incomplete => Future not completed. 5. Computation completed => • Future is completed. With a value => Success. • Future is completed. With an exception => Failure. 6. Result memoized by default.
  9. Callbacks & combinators • Callbacks: • onComplete * • for

    comprehension * • NOTE: • Callback “eventually” invoked only after future is completed. • for/ foreach invoked only if future successfully completes. • If multiple callbacks are registered on the future, order in which the callbacks are executed is not defined. * • (Chain callbacks) If a callback throws exc, others are executed regardless. • (Chain callbacks) If a callback never completes, others may not be executed. Use blocking construct. • Once executed, the callbacks are removed from the future object, thus being eligible for GC. • Combinators: • map, flatMap, foreach, filter etc. • recover, recoverWith, fallBackTo, andThen etc - Transformations. MS1 MS2 MS3 Main app Future.onComplete {…} Future.onComplete {…} Future.onComplete {…} Success Success Success Success DB Await.result(….)
  10. Promises • Writable, single-assignment operator. • Can use a promise

    to create a future or to complete a future. • Complete a future by fulfilling a promise. val p = Promise[Int]() val f = p.future p.complete(Success(1)) p.complete(Try(throw new Exception(“err”)) ——-> IllegalStateException:Promise already completed. • Future - for querying. Promise - to act on a future.
  11. Difference b/w Futures and Promises FUTURES PROMISES Centred around computation

    Centred around data * Can not be completed by client. Can be completed by client.
  12. Futures drawbacks • No referential transparency * • Memoization can

    be a curse. * • Not totally abstract. • Provide an execution context everywhere. • Eg: def task1(param: String)(implicit ec: ExecutionContext)
  13. Common misconceptions • Async and non-blocking are same. • Other

    common IO models - blocking, non-blocking, multiplex, asynchronous. • Eg: Swiggy partners (exercise) • Everything is better asynchronous! • Usually only good for I/O bound tasks. • Inserting futures everywhere will make it non-blocking.* • Blocking code will still be blocking.
  14. Writing async code is not good enough, writing correct and

    fully async code is the real challenge! Where did the exception I threw go? Why is my code still blocking? Why does my async code not utilise all of my cores? Why does my async code deadlock?
  15. References • https://docs.scala-lang.org/overviews/core/futures.html • https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html • https://stackoverflow.com/questions/2625493/asynchronous-vs-non-blocking • https://www.reddit.com/r/scala/comments/69loar/ meanings_and_levels_of_async_and_nonblocking/

    • https://blog.colinbreck.com/calling-blocking-code-there-is-no-free-lunch/ • https://accedia.com/blog/posts/accedia-blog/2019/07/22/introduction-to-asynchronous- programming-in-.net • https://medium.com/@sderosiaux/are-scala-futures-the-past-69bd62b9c001
  16. Suggested reads • Scala doc: https://docs.scala-lang.org/overviews/core/futures.html • https://danielwestheide.com/blog/the-neophytes-guide-to-scala-part-8-welcome-to-the-future/ • https://danielwestheide.com/blog/the-neophytes-guide-to-scala-part-9-promises-and-futures-in-

    practice/ • http://allaboutscala.com/tutorials/chapter-9-beginner-tutorial-using-scala-futures/ • https://alexn.org/blog/2017/01/30/asynchronous-programming-scala.html • https://medium.com/@shashankbaravani/consistency-models-in-distributed-systems-d64c134f84ce • https://www.ques10.com/p/2573/what-do-you-mean-by-a-consistency-model-explain--1/ • https://monix.io/presentations/2018-async-programming-yifan-xing.html