19

By executing this scala code, I don't have any output in the console. (I don't really understand what is happening)

If I remove Console.println("Console.println OK!") => everything seems fine.

If I remove Thread.sleep(2000) => everything seems fine.

Do you have any ideas about this ? Thank you very much!

Clément

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
import scala.language.postfixOps

object ScalaFuture {

  def main(args: Array[String]) {

    val f: Future[String] = Future {
      Thread.sleep(2000)
      "future value"
    }

    f.onSuccess {
      case s => {
        Console.println("Console.println OK!")
        System.out.println("System.out.println OK!")
      }
    }

    Await.ready(f, 60 seconds)
  }

}
dk14
  • 22,206
  • 4
  • 51
  • 88
ctamisier
  • 293
  • 1
  • 2
  • 9
  • Works fine for me. What happens if you sleep for a few seconds after `Await.ready` ? – Michael Zajac Jan 26 '15 at 22:44
  • If I sleep few seconds after `Await.ready` it works fine => I have the output. – ctamisier Jan 26 '15 at 23:06
  • Then it must be exiting before `onSuccess` can fire. – Michael Zajac Jan 26 '15 at 23:08
  • Yes exact, and it also exits while executing the code of `onSuccess` if I do more stuff in the function. So it seems hard to work with scala futures in a main function... I played a bit with the futures from twitter and I didn't (yet) have this problem, Maybe there is a mechanism to prevent this. I will check.. Thanks! – ctamisier Jan 26 '15 at 23:32
  • `onSuccess` is a wrapper for `onComplete`, which (as you may get it from the name) executes after future completes, so Await do not wait it in main thread. See my answer for solution. – dk14 Jan 27 '15 at 00:48

2 Answers2

32

Your await is waiting for future to complete, which is done after 2 seconds, but it doesn't wait for onSuccess handler, which executes in another thread (similar to future), but after Await.ready(f, 60 seconds), so process exits earlier than you print something. To process it correctly - create new future for onComplete:

val f: Future[String] = Future {
  Thread.sleep(2000)
  "future value"
}

val f2 = f map { s => 
    println("OK!")
    println("OK!")    
}

Await.ready(f2, 60 seconds)
println("exit")

Results for Await.ready(f, ...):

exit
OK!
OK!

Results for Await.ready(f2, ...):

OK!
OK!
exit
dk14
  • 22,206
  • 4
  • 51
  • 88
  • Ok great I understood. So if I am not wrong: this is a workaround when we use a main() function. Do you think that the ExecutionContext is involved in this and a "special" one can prevent this ?. I had a look on the Futures implemented by twitter and it seems that their "Scheduler" handles this (I don't need await.ready or wrap the future with the same use case), but this is another story. Thanks for your help ! – ctamisier Jan 27 '15 at 01:12
  • It's not workaround. It's a correct way to do such things (if you have only one thread with Await in your application) - especially for functional-style - as you have only one result in your application - you should return it (and so wait for it) to `IO` if your application is REPL-based (in other cases - user should shutdown it manually from UI so no need for awaits). Another option - is to use ExecutionContext (and underlying ThreadPool), which creates threads with `isDaemon` flag false - see http://stackoverflow.com/questions/16612517/execution-context-without-daemon-threads-for-futures. – dk14 Jan 27 '15 at 01:35
  • Why would `Await.ready(f, ...):` print out `OK!`? There's no `println("OK!")` in `f`. I don't know how to reconcile `f` with such an expected output. – Kevin Meredith Feb 25 '16 at 20:32
  • @KevinMeredith Because it's scala, not scalaz :). When you do `.map` here - you're actually adding a listener (in contrast to scalaz' `Future` which creates som free structure that requires explicit `run`). So, personally, I'd prefer scalaz approach as it's easier to reason about concurrency (managable non-determinizm etc.) – dk14 Feb 26 '16 at 06:49
  • 1
    @dk14 - I see, you're actually running that entire block of code, beginning with `val f = ...` for both `Await.ready(f, ...)` and `Await.ready(f2,...)`. Perhaps putting it within a `def` would make it clearer? – Kevin Meredith Feb 26 '16 at 15:21
  • @KevinMeredith Not exactly. the block inside f1 runs only once, regarless of two awaits. As I said it doesn't work like in scalaz, plain scala `Future` is mutable, and every `.map` call on it will add (using a fast compare-and-swap, but mutable operation) a new listener to it. So, with `def` it will be called twice, not once – dk14 Feb 26 '16 at 18:47
-19

Just put readLine() in your code.