I found this a bit confusing. I thought futures in scala are inmutable containers that once set, always return the same value.
So I have a future:
val y = future {Thread.sleep(1000); 1};
Now when i immediately (before the future resolves) pass it to Await.result
block twice:
Await.result(for (r1 <- y; r2 <- y) yield (r1, r2), 60 seconds)
I get a TimetoutException
.
However if i do it once the future is resolved, everything works fine and returns (1,1)
as expected.
What is the reason of this behavior?
Edit:
I'm using implicit ExecutionContext.Implicits.global
and scala.concurrent
@ scala 2.10.3
Edit2: If I create another future instance doing the same thing and do Await.result on them both it doesn't block.
Await. result tries to return the Future result as soon as possible and throws an exception if the Future fails with an exception while Await. ready returns the completed Future from which the result (Success or Failure) can safely be extracted.
Handle the result of a future with methods like onComplete , or combinator methods like map , flatMap , filter , andThen , etc. The value in a Future is always an instance of one of the Try types: Success or Failure.
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.
This appears to be an artifact of executing it in the REPL.
You can even reproduce it using 2 separate future instances, without any call to Thread.sleep
,
and using only pre-fulfilled futures (which means that there is not even any future thread involed).
Yes, seriously:
import scala.concurrent._
import duration._
import ExecutionContext.Implicits.global
val x = Future.successful(1)
val y = Future.successful(2)
Await.result(x.flatMap{_ => y.map{ _ => 0 } }, Duration(10, SECONDS)) // triggers a timeout
Interestingly this does not trigger any timeout if you change the last line to this:
Await.result(x.flatMap{_ => Future.successful(2).map{ _ => 0 } }, Duration(10, SECONDS))
It seems that the culprint is that your whole code snippet, when evaled in the REPL, is actually wrapped in an object.
This means that x
and y
here are actually members of the object, rather than local variables
More importantly, the call to Await is now part of the constructor of this wrapper object.
For some reason that I have yet to investigate, it seems to be the fact that the call to Await
is done in a constructor that triggers the blocking
(you can verify it easily by wrapping this call in a dummy class and instantiating it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With