Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is scala Await.result timing out in repl when passed the same future twice?

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.

like image 462
soulcheck Avatar asked Apr 16 '14 11:04

soulcheck


People also ask

What is await result in Scala?

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.

How do you handle Future Scala?

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.

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.


1 Answers

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).

like image 193
Régis Jean-Gilles Avatar answered Oct 13 '22 12:10

Régis Jean-Gilles