Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Futures do not run before program termination

I was trying to reproduce the example on new Scala 2.10 futures feature. The code I've used is:

import scala.concurrent.Future
import scala.concurrent.future

object Test {
    def main(args: Array[String]) {
     println("Test print before future")
     val s = "Hello"
     val f = future {s + " future!"}
     f onSuccess {case v => println(v)}
     println("Test print after future")
    }
}

Instead of printing:

Test print before future
Hello future!
Test print after future

It simply prints:

Test print before future
Test print after future

Any idea of why I have this behaviour? My version of scala compiler is 2.10.0-20120507.

like image 325
Vincenzo Maggio Avatar asked May 12 '12 16:05

Vincenzo Maggio


People also ask

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.

Is Scala future blocking?

By default, futures and promises are non-blocking, making use of callbacks instead of typical blocking operations. To simplify the use of callbacks both syntactically and conceptually, Scala provides combinators such as flatMap , foreach , and filter used to compose futures in a non-blocking way.

What are Scala promises?

Promise is an object which can be completed with a value or failed with an exception. A promise should always eventually be completed, whether for success or failure, in order to avoid unintended resource retention for any associated Futures' callbacks or transformations. Source Promise.scala. AnyRef, Any.


2 Answers

The issue is that you're executing that as a standalone program, whose main thread is terminating before one of the worker threads can execute the "Hello future!" println. (The threads that the new futures library spawns are daemon threads).

You can also use the Await object (also in scala.concurrent) to wait until the future f is completed:

import scala.concurrent._
import scala.concurrent.util._

object Test {
  def main(args: Array[String]) {
    println("Test print before future")

    val s = "Hello"
    val f = future {s + " future!"}
    f onSuccess {case v => println(v)}
    println("Test print after future")

    Await.ready(f, Duration.Inf)
  }
}

This can print:

Test print before future
Test print after future
Hello future!

Or, it can print "Hello future!" before "Test print after future" depending on the thread schedule.

Likewise, you can force the main thread to wait until f is completed before the last println as follows:

import scala.concurrent._
import scala.concurrent.util._

object Test {
  def main(args: Array[String]) {
    println("Test print before future")

    val s = "Hello"
    val f = future {s + " future!"}
    f onSuccess {case v => println(v)}

    Await.ready(f, Duration.Inf)        

    println("Test print after future")
  }
}

Which would print:

Test print before future
Hello future!
Test print after future

However, note that when you use Await, you're blocking. This of course makes sense to make sure that your main application thread doesn't terminate, but generally shouldn't be used unless necessary otherwise.

(The Await object is a necessary escape hatch for situations like these, but using it throughout application code without concern for its semantics can result in slower, less-parallel execution. If you need to ensure that callbacks are executed in some specified order, for example, there are other alternatives, such as the andThen and map methods on Future.)

like image 154
Heather Miller Avatar answered Dec 11 '22 09:12

Heather Miller


I think that problem here is timing. Most probably your future code is running in separate deamon thread. I think that application finishes very fast and this deamon thread do not have enough time to execute properly (application does not wait for deamon threads to finish). But this also very system-dependent behavior. For me it prints:

Test print before future
Test print after future
Hello future!

and then exits (I'm using Scala 2.10.0-M3). You can try following in order to test it - just put main execution thread in sleep for several seconds and see whether Hello future! is printed:

import scala.concurrent.Future
import scala.concurrent.future

object Test {
    def main(args: Array[String]) {
        println("Test print before future")

        val s = "Hello"
        val f = future {s + " future!"}
        f onSuccess {case v => println(v)}

        println("Test print after future")

        Thread.sleep(3000) 
        println("Test print at the end.")
    }
}
like image 45
tenshi Avatar answered Dec 11 '22 09:12

tenshi