Futures and Promises: Functional Way of Concurrency

Reading Time: 3 minutes

So, from the heading, you must be wondering that what is so special about Futures and Promises and why we are calling it the functional way of concurrency.

Well, you all must be aware of the problems that are associated with concurrent programming whether it’s debugging a multithreaded program or shared state concurrency and that’s where Futures and Promises help you so that you don’t stick with these problems and let you code concurrently.

Now let’s dive deep and understand what actually Futures and Promises are.

What is Future?

A Future is an object that holds a value that may become available, as its name suggests, at a later time. The simplest way to create a Future is by using apply method.

def someFuture[T]: Future[T] = Future {
someComputation()
}

Things to keep in mind while using Futures

  • Futures apply method contains two method: body & and an implicit executor ExecutionContext so you have to import:
import scala.concurrent.ExecutionContext.Implicits.global
 //ExecutionContext is used to handle the thread allocation for Futures
  • You have to use onComplete callback method in order to compute your computation.
someFuture.onComplete {
case Success(result) => println(result)
case Failure(t) => t.printStackTrace
}

What is Promise?

Future can also be constructed using Promise. The promise is considered as a writable, single assignment container. You can use Promise to create a Future which will be completed when Promise is fulfilled with a value.

val promise: Promise[String] = Promise[String]()
val future = promise.future
...
val anotherFuture = Future {
...
promise.success("Done")
doSomethingElse()
}
...
future.onSuccess { case msg => startTheNextStep() }

Future in Action

We will be implementing the word count problem using Future. Let’s break this problem into four steps:

  • Scan for all the files in a given directory
  • Count words in a given file
  • Accumulate and sort the result
  • Produce the result

Scan for all the files in a given directory

Scanning files in a given directory can be done asynchronously :

private def scanFiles(docRoot: String): Future[Seq[String]] = Future {
new File(docRoot).list.map(docRoot + _)

Count words in a given file

Similarly, we can count words for a given file inside a Future. If something goes wrong
we can use the recovery method to register a fallback:

private def processFile(fileName: String): Future[(String, Int)] =
Future {
val dataFile = new File(fileName)
val wordCount =
Source
.fromFile(dataFile).getLines.foldRight(0)(_.split(" ").size + _)
(fileName, wordCount)
} recover {
case e: java.io.IOException =>
println("Something went wrong " + e)
(fileName, 0)
}

The recover callback will be invoked if IOException is thrown inside the Future and each file will end up with a collection of futures like:

val futures: Seq[Future[(String, Int)]] =
fileNames.map(name => processFile(name))

Accumulate and sort the result

The above invokes is a problem as we can not possibly register callbacks with each future since they can complete at different times. So we will accumulate the result and sort them:

val singleFuture: Future[Seq[(String, Int)]] = Future.sequence(futures)

You can invoke the map method in the future to sort the result:

private def processFiles(
fileNames: Seq[String]): Future[Seq[(String, Int)]] = {
val futures: Seq[Future[(String, Int)]] =
fileNames.map(name => processFile(name))
val singleFuture: Future[Seq[(String, Int)]] = Future.sequence(futures)
singleFuture.map(r => r.sortWith(_._2 < _._2))
}

One thing to notice is Future is an example of a monad snd therefore it implements map, flatmap, and filter. You can compose scanFiles and processFiles to produce the sorted result:

val path = "src/main/resources/"
val futureWithResult: Future[Seq[(String, Int)]] = for {
files <- scanFiles(path)
result <- processFiles(files)
} yield {
result
}

Produce the Result

For the last step, we can use a Promise that will be fulfilled when futureWithResult completes.

To get the whole implementation of the word count example you can refer to the following link.

Conclusion

Well thank you so much for making it to the end of this blog and I hope by reading this blog you must have gained some knowledge of Future and Promise, in order to get a deep understanding you can go through the documentation.

References

https://docs.scala-lang.org/overviews/core/futures.html

Written by 

Hi community, I am Raviyanshu from Dehradun a tech enthusiastic trying to make something useful with the help of 0 & 1.

1 thought on “Futures and Promises: Functional Way of Concurrency3 min read

Comments are closed.

%d bloggers like this: