Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested Future.sequence executes included Futures sequentially

I have a future(doFour) that is executed and results passed to a flatmap. Inside the flatmap I execute two more future(doOne and doTwo) functions expecting them to run on parallel but I see they are running sequentially (2.13). Scastie

Why are doOne and doTwo not execute in parallel ?

How can I have them to run in parallel ?

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}

object Test {
  def doOne(): Future[Unit] = Future {
    println("startFirst");      Thread.sleep(3000);     println("stopFirst")
  }

  def doTwo(): Future[Unit] = Future {
    println("startSecond");      Thread.sleep(1000);      println("stopSecond")
  }


  def doFour(): Future[Unit] = Future {
    println("do 4");     Thread.sleep(1000);     println("done 4")

  }


  def main(args: Array[String]) {


    val resOut = doFour().flatMap { a =>

      val futureOperations = Seq(doOne(), doTwo())

      val res = Future.sequence(futureOperations)
      res
    }

    val stream = Await.result(resOut, Duration.Inf)
  }
}
like image 917
nirfri Avatar asked Apr 24 '20 05:04

nirfri


People also ask

What is Future sequence?

This Future. sequence() function converts a list of Futures into a single Future that means collections of Futures into a single Future. In simple words, List[Future[T]] ======> Future[List[T]] . It is also known as composing Futures.

How does Future work in Scala?

Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.

What is Future and promise in Scala?

The Promise is a writable, single-assignment container that completes a Future. The Promise is similar to the Future. However, the Future is about the read-side of an asynchronous operation, while the Promise is about the write-side.

What is Future object in Scala?

A Future is a placeholder object for a value that may not yet exist. Generally, the value of the Future is supplied concurrently and can subsequently be used. Composing concurrent tasks in this way tends to result in faster, asynchronous, non-blocking parallel code.


1 Answers

A Future becomes eligible for execution as soon as it is created. So this line creates two Futures that can potentially be executed:

val futureOperations = Seq(doOne(), doTwo())

The call to Future.sequence will create a new Future that waits for each of the futures to complete in turn, but they will both already be available for execution by this point in the code.

val res = Future.sequence(futureOperations)

If you want Futures to start sequentially you need to use map/flatMap:

val res = doOne().map( _ => doTwo())

With this code doTwo will not be called until doOne completes (and not at all if doOne fails)

The reason that this does not appear to happen in your example is that you are calling a blocking operation in your Future which is blocking a thread that would otherwise be used to execute other Futures. So although there are two Futures available for execution, only one is actually being executed at a time.

If you mark the code as blocking it works correctly:

import scala.concurrent.blocking

def doOne(): Future[Unit] = Future {
  blocking{println("startFirst");      Thread.sleep(3000);     println("stop First")}
}

def doTwo(): Future[Unit] = Future {
  blocking{println("startSecond");      Thread.sleep(1000);      println("stop Second")}
}

See the comments section for details of why the default behaviour is different on different versions, and why you should never make assumptions about the relative execution order of independent Futures.

like image 147
Tim Avatar answered Sep 27 '22 02:09

Tim