Scala Future calling lazy method inside block is not working - scala

Problem:
I am trying to call lazy function(function assigned to lazy val) inside Future block and it is not behaving as expected but when i execute the function directly inside the block it is working as expected. Not sure if am missing any.
Working Code:
Below is the code working as expected when i execute the method directly inside Future block
implicit val ec = ExecutionContext.fromExecutorService {
Executors.newFixedThreadPool(8)
}
def execute1() = {
Thread.sleep(4000); println("Completed 1!!!")
1
}
def execute2() = {
Thread.sleep(3000); println("Completed 2!!!")
2
}
def execute3() = {
Thread.sleep(2000); println("Completed 3!!!")
3
}
def execute4() = {
Thread.sleep(1000); println("Completed 4!!!")
4
}
val future1 : Future[Int] = Future.apply(execute1())
val future2 : Future[Int] = Future.apply(execute2())
val future3 : Future[Int] = Future.apply(execute3())
val future4 : Future[Int] = Future.apply(execute4())
val result = for { r1 <- future1
r2 <- future2
r3 <- future3
r4 <- future4
} yield {
println(r1+","+r2+","+r3+","+r4)
}
StdIn.readLine()
sys.exit()
When the above code is executed, the methods are executed in order "execute4,execute3,execute2,execute1" which is as expected.
Not Working Code:
In the above code, when i trying assigning the "execute" method to lazy variable and refer that variable inside Future block it is behaving differently. It is executed in 1,4,3,2 order.. Please see below code
implicit val ec = ExecutionContext.fromExecutorService {
Executors.newFixedThreadPool(8)
}
def execute1() = {
Thread.sleep(4000); println("Completed 1!!!")
1
}
def execute2() = {
Thread.sleep(3000); println("Completed 2!!!")
2
}
def execute3() = {
Thread.sleep(2000); println("Completed 3!!!")
3
}
def execute4() = {
Thread.sleep(1000); println("Completed 4!!!")
4
}
lazy val e1 = execute1()
lazy val e2 = execute2()
lazy val e3 = execute3()
lazy val e4 = execute4()
val future1 : Future[Int] = Future.apply(e1)
val future2 : Future[Int] = Future.apply(e2)
val future3 : Future[Int] = Future.apply(e3)
val future4 : Future[Int] = Future.apply(e4)
val result = for { r1 <- future1
r2 <- future2
r3 <- future3
r4 <- future4
} yield {
println(r1+","+r2+","+r3+","+r4)
}
StdIn.readLine()
sys.exit()
Expected Behavior: Since the functions(e1,e2,e3,e4) are referred as Lazy, it should be executed inside Future block upon calling and should behave same as the working code. Weird behavior i notice is it executes execute1() method synchronously and rest of the methods asynchronously.. Any guidance or suggestion will be great to me..
Output I am Expecting:
Regardless of "i execute the method inside Future block"(or) "make the method as lazy outside the Future block and call inside the Future block" should yield me the same result.. As per my example, the output i am expecting is "the order of method execution(asynchronously) as execute4(),execute3(),execute2() and execute(1)"
To simplify the example..
Future Execution is different in below two approach.. In both the approach, i am expecting same output
//Approach#1
def method() = {
}
Future{
method()
}
//Approach#2
lazy val lazyMethod = method()
Future {
lazyMethod()
}

Actually the code is working as expected. Let me explain.
First comes the for, when you did,
val result = for {
r1 <- future1
r2 <- future2
r3 <- future3
r4 <- future4
} yield {
println(r1+","+r2+","+r3+","+r4)
}
You are roughly doing,
val result =
future1.flatMap(r1 =>
future2.flatMap(r2 =>
future3.flatMap(r3 =>
future4.map(r4 =>
println(r1+","+r2+","+r3+","+r4)
)
)
)
)
Which means you are "accessing" the values computed by these futures only after you have accessed the value of the previous one.
Now comes the Future.apply which takes a body: => T as argument and gives you a Future[T] but the thing is that this body will start executing as soon as you create the future.
So, In your first implementation when you did,
val future1 : Future[Int] = Future.apply(execute1())
val future2 : Future[Int] = Future.apply(execute2())
val future3 : Future[Int] = Future.apply(execute3())
val future4 : Future[Int] = Future.apply(execute4())
All these futuresI's began executing your executeI's at this point. So, the println inside these executeI's will be executed x ms after this, irrespective of when you try to access the value inside any of these futures.
Now, comes the lazy. So when you declare something like this,
val laxy x = {
println("accessing lazy x")
5
}
The block will be executed only when you access x for the first time.
And when you are doing this,
val future1 : Future[Int] = Future.apply(e1)
val future2 : Future[Int] = Future.apply(e2)
val future3 : Future[Int] = Future.apply(e3)
val future4 : Future[Int] = Future.apply(e4)
You are still not "accessing" any of these lazy eI's but as you know that each future starts computing as soon as it is created. So when these futures start executing they will "access" these eI's.
To understand it better, lets change our executeI's as following,
def execute1() = {
println("Started 1!!! " + System.currentTimeMillis())
Thread.sleep(4000)
println("Completed 1!!! " + System.currentTimeMillis())
1
}
And you will notice that all of these eI's are executing sequentially.
This is because all these eI's will be evaluated in the thread where these were defined and not in the thread executing the Future. So these Thread.sleep will block the current thread and will be evaluated in a non-deterministic order (owing to some probable optimizations), which co-incidentally happens to be 1, 4, 3, 2.
But if you change the order of future to,
val future1 : Future[Int] = Future.apply(e1)
val future4 : Future[Int] = Future.apply(e4)
val future2 : Future[Int] = Future.apply(e2)
val future3 : Future[Int] = Future.apply(e3)
It will become 1, 3, 2, 4.

Related

How to make sure a given future completes first in tests?

I'm writing tests for function bar:
def bar(fut1: Future[Int],
fut2: Future[Int],
fut3: Future[Int]): Future[Result] = ???
bar returns Result like this:
case class Result(
x: Int, // fut1 value
oy: Option[Int], // if fut2 is complete then Some of fut2 value else None
oz: Option[Int] // if fut3 is complete then Some of fut3 value else None
)
I want to write tests for all test cases:
fut1 completed, fut2 and fut3 did not complete
fut1 completed, fut2 completed, fut3 did not complete
etc.
So I am writing a fake implementation of functions foo1, foo2, and foo3 for these tests.
def foo1(x: Int): Future[Int] = ???
def foo2(x: Int): Future[Int] = ???
def foo3(x: Int): Future[Int] = ???
Test #1 invokes all these functions, checks if fut1 completes first, and invokes bar
val fut1 = foo1(0)
val fut2 = foo2(0)
val fut3 = foo3(0)
// make sure `fut1` completes first
Test #2 invokes all these functions, makes sure that fut2 completes first, and invokes bar.
Test #3 invokes all these functions, makes sure that fut3 completes first, and invokes bar.
My question is how to implement the functions foo1, foo2, and foo3 and the tests.
You can try attach completeness timestamp to each future via map, like:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.concurrent.duration._
import scala.language.postfixOps
def foo1(x: Int): Future[Int] = Future {Thread.sleep(200); 1}
def foo2(x: Int): Future[Int] = Future {Thread.sleep(500); 2}
def foo3(x: Int): Future[Int] = Future {Thread.sleep(500); 3}
def completeTs[T](future: Future[T]): Future[(T, Long)] = future.map(v => v -> System.currentTimeMillis())
val resutls = Await.result(Future.sequence(
List(completeTs(foo1(1)), completeTs(foo2(1)), completeTs(foo3(1)))
), 2 seconds)
val firstCompleteTs = resutls.map(_._2).min
val firstCompleteIndex = resutls.indexWhere(_._2 == firstCompleteTs)
assert(firstCompleteIndex == 0)
Scatie: https://scastie.scala-lang.org/L9g78DSNQIm2K1jGlQzXBg
You could repurpose firstCompletedOf to verify whether the future of a given index in the futures list is the first completed one:
import java.util.concurrent.atomic.AtomicReference
import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.Try
def isFirstCompleted[T](idx: Int)(futures: List[Future[T]])(
implicit ec: ExecutionContext): Future[Boolean] = {
val promise = Promise[(T, Int)]()
val pRef = new AtomicReference[Promise[(T, Int)]](promise)
futures.zipWithIndex foreach { case (f, i) => f onComplete { case tt: Try[T] =>
val p = pRef.getAndSet(null)
if (p != null) p tryComplete tt.map((_, i))
}
}
promise.future.map{ case (t, i) => i == idx }
}
Test running:
import scala.concurrent.ExecutionContext.Implicits.global
val futures = List(
Future{Thread.sleep(100); 1},
Future{Thread.sleep(150); throw new Exception("oops!")},
Future{Thread.sleep(50); 3}
)
isFirstCompleted(0)(futures) // Future(Success(false))
isFirstCompleted(2)(futures) // Future(Success(true))
For writing test cases, consider using ScalaTest AsyncFlatSpec.
It is unclear what it is exactly you are trying to test.
If you simply use futures that have already completed, you will get the behavior you describe:
def f1 = Future.successful(1)
def f2 = Future.successful(2)
def f3 = Future.successful(3)
eventually {
Future.firstCompletedOf(Seq(f1, f2, f3)).value shouldBe Some(1)
}
(note, that you cannot compare directly with fut1 like you did in the question, that'll always be false, because .firstCompletedOf returns a new future).
You can also make only one future complete, and leave the others alone:
val promise = Promise[Int].future
def f1 = promise.future // or just Future.successful(1) ... or Future(1)
def f2 = Future.never
def f3 = Future.never
result = Future.firstCompletedOf(Seq(f1, f2, f3))
promise.complete(Success(1))
eventually {
result.value shouldBe 1
}
Etc ... Can make the other futures be backed by their own promise too for example, if you want them all to complete eventually (not sure what it'll gain you, but then again, I am not sure what you are testing here to begin with).
Another possibility is make them depend on each other:
val promise = Promise[Int]
def f1 = promise.future
def f2 = promise.future.map(_ + 1)
def f3 = promise.future.map(_ + 2)
...
promise.complete(Success(1))

How to test if futures run sequentially in Scala?

Suppose I have this methods:
def callApis(f1, f2, f3):Future[Result] {
for {
a <- Future { f1 }
b <- Future { f2 }
c <- Future { f3 }
} yield Result(a,b,c)
}
If you are familiar with scala you will know that lines in the for block will execute sequentially. More specific, a will be calculated first. Then when we have the result for a, the code will calculate b. Then when we have the result for b, the code will calculate c.
My question is, how can you write a UNIT TEST that ensures that a always be computed before calculating b, and b always be computed before calculating c? My fear is if someone doesn't know much about how futures work in scala. They can accidentally make this code to run asynchronously.
I mean people can accidentally do something like this, this makes a,b,c to be calculated asynchronously (which I don't want people to do):
def callApis(f1, f2, f3):Future[Result] {
val fut1 = Future { f1 }
val fut2 = Future { f2 }
val fut3 = Future { f3 }
for {
a <- fut1
b <- fut2
c <- fut3
} yield Result(a,b,c)
}
Perhaps try defining a single-threaded execution context and require it in blocks that should execute serially. For example,
trait SerialExecutionContext extends ExecutionContext {
val singleThreadPool = Executors.newFixedThreadPool(1, (r: Runnable) => new Thread(r, s"single-thread-pool"))
val serialEc = ExecutionContext.fromExecutor(singleThreadPool)
override def execute(runnable: Runnable): Unit = serialEc.execute(runnable)
override def reportFailure(cause: Throwable): Unit = serialEc.reportFailure(cause)
}
def callApis()(implicit ec: SerialExecutionContext): Future[Result] = {
val fut1 = Future { ...doSomething... }
val fut2 = Future { ...doSomething... }
val fut3 = Future { ...doSomething... }
for {
a <- fut1
b <- fut2
c <- fut3
} yield Result(a,b,c)
}
Now callApis can evaluate only if we can prove at compile time there exists a serial execution context. Since within the body we have only one thread available futures are forced to start only after the previous one finished.

How to resolve a Future inside another Future

I want to create a function similar to the following. Basically the function, say F will create a Future say fut1. When fut1 resolves, then another Future say fut2 should get created inside fut1. The fut2 should return the final value of the function F. The code has to be non-blocking all the way. I have written something like this but the return type is not Future[Int] but Future[Future[Int]]. I understand why this is the case (because map creates a Future) but I am unable to figure out how to return Future[Int] from this code.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def fut:Future[Int] = {
val f1 = Future{ 1 } //create a Future
f1.map (x => { //when f1 finishes, create another future
println(x)
val f2 = Future{ 2 }
f2.map(x=> x) //this creates another Future and thus the return is Future[Future[Int]]
})
}
You can achieve this using flat map or for comprehension.
FlatMap-
def futureFunctionWithFlatMap: Future[Int] = {
val f1 = Future {
1
}
f1.flatMap(x => {
println(x)
val f2 = Future {
2
}
f2.map(x => x)
})
}
For Comprehension
def futureFunctionWithForComprehension: Future[Int] = {
for {
f1 <- Future { 1 }
f2 <- {
println(f1)
Future { 2 }
}
} yield f2
}
Use flatMap
val f1 = Future{ 1 } //create a Future
val f2: Future[Int] = f1.flatMap(x => {
//will be triggered only after x is ready
Future{2}
})

Waiting for another future to end to return a function

Let's say I have a function func1 that needs to return a Future with two integers. Each of the two values are returned by independent futures, like so:
def f1 = Future { 1 }
def f2 = Future { 2 }
def func1 : Future[(Int,Int)] = {
val future1 = f1
future1.map { result1 =>
result1 * 10
}
val future2 = f2
future2.map { result2 =>
result2 * 20
}
}
I need future1 wait until future2 ends (or vice versa) to return both results as (Int,Int). How can this be accomplished?
That's precisely what the zip method on futures does:
val futurePair: Future[(Int, Int)] = future1.zip(future2)
Note that if you haven't instantiated your futures before (say, if future1 and future2 are defs, not vals), this will run the two computations in parallel, while a for comprehension (or flatMap) would wait for the first one to succeed before starting the second one.
A for-comprehension is the best option here:
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> import concurrent.ExecutionContext.Implicits.global
import concurrent.ExecutionContext.Implicits.global
scala> def f1 = Future{1}
f1: scala.concurrent.Future[Int]
scala> def f2 = Future{2}
f2: scala.concurrent.Future[Int]
scala> for {result1 <- f1; result2 <- f2} yield (result1 * 10, result2 * 20)
res0: scala.concurrent.Future[(Int, Int)] = scala.concurrent.impl.Promise$DefaultPromise#71f67a79
More information can be found here and here.
Note: this will run the two Futures in sequence while Cyrille Corpet's solution will run them in parallel.
You can use a for-comprehension for futures that have already started like this:
val f1: Future[Int] = ???
val f2: Future[Int] = ???
val f3: Future[Int] = ???
val futureInts: Future[(Int, Int, Int)] = for {
result1 <- f1
result2 <- f2
result3 <- f3
} yield (result1, result2, result3)
If the futures were assigned to lazy vals or defs then this wouldn't work, because the futures would not have been started (if you start the futures inside the for comprehension, then they will be executed sequentially). Here is an example of starting them, and then waiting for them with for.
Example:
val f1: Future[Int] = Future {
println("starting f1")
Thread.sleep(1000)
1
}
val f2: Future[Int] = Future {
println("starting f2")
Thread.sleep(3000)
2
}
val f3: Future[Int] = Future {
println("starting f3")
Thread.sleep(2000)
3
}
val futureInts: Future[(Int, Int, Int)] = for {
result1 <- f1
result2 <- f2
result3 <- f3
} yield (result1, result2, result3)
futureInts.map {
case tuple => println(tuple)
}
Output:
starting f1 // These first
starting f3 // threes statements
starting f2 // happen right away.
(1,2,2) // Then this prints a three seconds later
In your case you could do this:
def func1 : Future[(Int,Int)] = {
// Start futures
val future1 = f1.map(_ * 10)
val future2 = f2.map(_ * 20)
// Wait for both futures, and return a tuple
for {
result1 <- future1
result2 <- future2
} yield (result1, result2)
}

Interesting map and flatMap observations - Future, Scala

I noticed few interesting behaviour about map, flatMap and Future but I am not able to understand what is causing this behaviour
//I have 3 Future objects.
object ConcurrencyExample extends App {
val time = System.currentTimeMillis()
val future1 = Future{println("future1");1}
val future2 = Future{println("future2");2}
val future3 = Future{println("future3");3}
//I want to add 1,2 and 3. I can do it using flatMap
val result = future1 flatMap (f1=> future2.flatMap(f2 => future3.map(f3=> f3+f2+f1) ) )
result onComplete{
case Success(v)=>println("result is "+v)
case Failure(e) =>println("failed result:"+e)
}
Thread.sleep(1000)
}
result
future2
future1
future3
result is 6
If I change the code above to map, I get an empty List(). I am unable to track where this empty List came from?
val result = future1 map (f1=> future2.map(f2 => future3.map(f3=> f3+f2+f1) ) )
result
future3
future2
future1
result is List()
If I use only two Future objects and map, I get Success(3) and not an empty List()
val result = future1 map (f1=> future2.map(f2 => f2+f1) )
result
future3
future2
future1
result is Success(3)
In the first case the result return type is Future[Int], In the second case the result return type is Future[Future[...]] (some nested Future)
In the first case when you do the onComplete that is
val result: Future[Int] = ???
result onComplete { println }
The above code will return Success(1)
In the second case
val result: Future[Future[..]] = ???
result onComplete { println }
This may result unevaluated Future that is why you see List(). See the Scala repl output below. Look at the result type of Future { Thread.sleep(1000); 1 }
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> val f = Future { Thread.sleep(1000); 1 }
f: scala.concurrent.Future[Unit] = List()
scala> f onComplete { println }
Success(1)
Suggestion
Know the difference between flatMap and map and know when to use flatMap and map.