Saturday, 11 July 2015

Concurrency with Futures in Akka

future gives you a simple way to run an algorithm concurrently. A future starts running concurrently when you create it and returns a result at some point, well, in the future. In Scala,it’s said that a future returns eventually.

A future and ExecutionContext

The following statements describe the basic concepts of a future, as well as the ExecutionContext that a future relies on.
  • Future[T] is a container that runs a computation concurrently, and at some future time may return either (a) a result of type T or (b) an exception.
  • Computation of your algorithm starts at some nondeterministic time after the future is created, running on a thread assigned to it by the execution context.
  • The result of the computation becomes available once the future completes.
  • When it returns a result, a future is said to be completed. It may either be successfully completed, or failed.
  • As shown in the examples, a future provides an interface for reading the value that has been computed. This includes callback methods and other approaches, such as a for comprehension, mapflatMap, etc.
  • An ExecutionContext executes a task it’s given. You can think of it as being like a thread pool.
  • The ExecutionContext.Implicits.global import statement shown in the examples imports the default global execution context.

Callback methods

The following statements describe the use of the callback methods that can be used with futures.
  • Callback methods are called asynchronously when a future completes.
  • The callback methods onCompleteonSuccessonFailure, are demonstrated in the Solution.
  • A callback method is executed by some thread, some time after the future is completed. From the Scala Futures documentation, “There is no guarantee that it will be called by the thread that completed the future or the thread that created the callback.”
  • The order in which callbacks are executed is not guaranteed.
  • onComplete takes a callback function of type Try[T] => U.
  • onSuccess and onFailure take partial functions. You only need to handle the desired case. (See Recipe 9.8 for more information on partial functions.)
  • onCompleteonSuccess, and onFailure have the result type Unit, so they can’t be chained. This design was intentional, to avoid any suggestion that callbacks may be executed in a particular order.

For comprehensions (combinators: map, flatMap, filter, foreach, recoverWith, fallbackTo, andThen)

As shown in the Solution, callback methods are good for some purposes. But when you need to run multiple computations in parallel, and join their results together when they’re finished running, using combinators like mapforeach, and other approaches, like a for comprehension, provides more concise and readable code. The for comprehension was shown in the Solution.
The recoverrecoverWith, and fallbackTo combinators provide ways of handling failure with futures. If the future they’re applied to returns successfully, you get that (desired) result, but if it fails, these methods do what their names suggest, giving you a way to recover from the failure.
As a short example, you can use the fallbackTo method like this:
val meaning = calculateMeaningOfLife() fallbackTo 42
The andThen combinator gives you a nice syntax for running whatever code you want to run when a future returns, like this:
var meaning = 0
future {
  meaning = calculateMeaningOfLife()
} andThen {
  println(s"meaning of life is $meaning")
}

No comments:

Post a Comment