2

I am learning scala futures and I hit my question already. I have a very simple example

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}
/**
 * Created by dummy on 05/02/15.
 */
object FutureUtils extends App{

  val f = Future {
    Thread.sleep(1000)
    println("I am learning scala futures")
    "learning"
  }

  f onComplete {

    case Success(value:String) => println("got the response back")
    case Failure(t: Throwable) => println("did not expect this")

  }

  println("I am still learning")

}

When I run the program as-is output never prints

got the response back

instead looks like it hangs for a minute or so and ends without printing the expected output ever. I am sure I am missing something very basic here.

I also tried adding System.in.read() at the end and it seems when I input any dummy value, programs ends printing expected result. What is the reason behind this behavior? Could anyone please help me understand this?

JavaMan
  • 351
  • 1
  • 3
  • 13
  • Don't mix `Thread.sleep()` with futures. Futures execute in their own exectution context ( some other thread of some thread-pool). – sarveshseri Feb 05 '15 at 19:18
  • I just wanted to simulate an asynchronous call. Pretend as if the call took a second or so – JavaMan Feb 05 '15 at 19:21
  • You don't need that there. It will work... even without that the future will get evaluated asynchronously. – sarveshseri Feb 05 '15 at 19:27
  • Because... your future is taking at least 1 second to get resolved. In that 1 second, the App thread will execute and complete... without hearing anything from the future. That's why removing `Thread.sleep() ` is important. – sarveshseri Feb 05 '15 at 19:38
  • The reason why your App is shutting down before another thread (created for `Future`) is completed - is that `Implicits.global`'s ThreadPool is creating daemon threads by default (so application will not wait them). related answer - http://stackoverflow.com/questions/28160021/using-futures-and-thread-sleep (see comments about pool) – dk14 Feb 08 '15 at 02:12

3 Answers3

5

The reason the program doesn't work without the System.in.read() is that onComplete does not block until the future completes but merely adds a callback for when it does. That callback never gets executed because the whole program ends before the future completes. To fix this problem, you could deliberately let the main thread go into an infinite loop and explicitly terminate the process in the callback.

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}

object Main extends App {
  val f = Future {
    Thread.sleep(1000)
    println("I am learning scala futures")
    "learning"
  }
  f onComplete {
    case Success(value:String) => println("got the response back"); System.exit(0)
    case Failure(t: Throwable) => println("did not expect this"); System.exit(1)
  }
  println("I am still learning")
  while (true){
    Thread.sleep(1000)
  }
}
Kim Stebel
  • 41,826
  • 12
  • 125
  • 142
  • 2
    Another approach would be use either the `ready` or `result` method in object `scala.concurrent.Await` to wait for `f` to complete before proceeding. – Daryl Odnert Feb 05 '15 at 22:54
  • Well!!! I don't get it completely. In my example all the future block does is sleep for 1 second and return a dummy string. If a simple example as this requires my main thread to be alive for around 1 minute or so. What about more complex examples, such as Spray client? From this I understand that either I need to block using Await or use any other way to make sure my main thread stays alive till the future gets completed and also I need to terminate the main thread explicitly. – JavaMan Feb 06 '15 at 04:34
  • 2
    Let's just hope people don't extend this advice to any real program where context switching and the stack space occupied by sleeping threads actually matter. Sad part is, the proper solution is actually shorter and easier to understand. – Rich Henry Feb 06 '15 at 14:30
  • I intentionally tried to stay as close to JavaMan's code as possible. Since it's a toy programme anyway, that seemed to matter more than concerns about creating one extra thread. Also, the solution with Await.result does not explain anything about how `onComplete` works. – Kim Stebel Feb 06 '15 at 14:33
  • Using `sleep` just introduces a race condition. This is exactly the kind of code you don't want to write. If he must use `onComplete` he should use some form of formal synchronization to ensure completion, but in this case he just shouldn't use it. – Rich Henry Jul 21 '16 at 20:17
3

You need to await the future, the program is exiting before it completes.

import scala.concurrent.Await
import scala.concurrent.duration._

var myFuture = Future {
    Thread.sleep(1000)
    1
}

// oncomplete handlers, etc here

println(Await.result(myFuture, 5 seconds))

EDIT: If you must use onComplete and can't verify that those handlers are executed before Await.ready/result then you should use formal synchronization, i.e.:

import scala.concurrent._
import java.util.concurrent.CountDownLatch

object Main extends App {
  val f = Future {
    Main.synchronized {
      Thread.sleep(1000);
      1
    }
  }

  val latch = new CountDownLatch(1)

  f.onComplete {
    case _ => { latch.countDown() }
  }

  latch.await()
}
Rich Henry
  • 1,837
  • 15
  • 25
  • Using Await will wait until the Future is complete, but the script might still exit before the onComplete handlers fire (since they, by definition, happen after the future completes). – tunesmith Apr 21 '16 at 20:34
  • You don't need `onComplete` anymore if you use `Await.result` in this way, you just match on the result. – Rich Henry Jul 21 '16 at 20:14
0

Well... since you are sleeping for 1000 miliseconds inside your future, your future will take at least 1 second to complete. The app thread completes itself and exits in this time.

You have to make sure that the app thread is alive when the future completes. You can do this by sleeping in your app thread for some time... like this.

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}

object FutureUtils extends App{

  val f = Future {
    Thread.sleep(1000)
    println("I am learning scala futures")
    "learning"
  }

  f onComplete {
    case Success(value:String) => println("got the response back")
    case Failure(t: Throwable) => println("did not expect this")
  }

  // Wait for some time
  // Not sure future will complete in this time or not
  Thread.sleep(1000);
  Thread.sleep(1000);
  Thread.sleep(1000);
}

But, the better way to do this is by making it so that the app thread needs the future to complete.

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{ Failure, Success }

object FutureUtils extends App {

  val f = Future {
    Thread.sleep( 1000 )
    println( "I am learning scala futures" )
    "learning"
  }

  f onComplete {
    case Success( value:String ) => println( "got the response back" )
    case Failure( t: Throwable ) => println( "did not expect this" )
  }

  while ( f.value == None ) {
    // Waste time just till the future is complete.
  }

  // Do something with future value.
  f.foreach( ( s: String ) => println( s ) )

}
sarveshseri
  • 13,738
  • 28
  • 47
  • So... someone downvoted without leaving any comment... Great... :D ... I think I will leave a comment on their behalf. – sarveshseri Feb 05 '15 at 20:37
  • 2
    I didnt downvote you, but you should not sleep to wait for a future. There is a utility called `scala.concurrent.Await` that does it safely and accurately. Sleeping for synchronization is introducing what is basically a race condition. I get annoyed when people do that to me to, just how it goes. – Rich Henry Feb 05 '15 at 23:24
  • Well... I did not say that we should sleep. Read the answer, I said we need to make sure the thread lives long enough... this was more about making him understand why his code is not working... and how to fix it simply without adding more concepts. – sarveshseri Feb 06 '15 at 00:46
  • Didn't downvote either - but stackoverflow isn't about "fix my code" - it's more about research the problem and using best and common solution. Otherwise we will have to deal with every spagetti-code question, which is undesirable here. You could ask about on meta.stackoverflow - if you don't believe me. If smbdy research scala deeply enough and found Futures - then he should know about Await, otherwise - next his question will contain `while(flag == false) Thread.sleep(1000)` – dk14 Feb 08 '15 at 01:28
  • More than that - you've added redundant concept here (promises) without clear explanation about how they work. And actually you don' know how they work as code inside `p.future.onComplete` will be executed in **another** thread, so your `p.success` will not wait for `println` inside `onComplete` automatically as you may think. Your code may print nothing - so answer is wrong. Just think - why p.future requires implicit thread pool to be specified. You can also try to print your `Thread.currentThread` inside onComplete - it won't be "main" - it will be some thread from the pool. – dk14 Feb 08 '15 at 01:55
  • I also would recommend you to check your code snippets with "Scala REPL" before posting here - as for example, there is no `forEach` method in scala - there is `foreach`, scala is case-sensitive. If you repeatedly ignore elemental things - you may deservedly get "-1" here, we are so grammar-nazi! – dk14 Feb 08 '15 at 02:02
  • Well @dk... I did check but I did not copy paste... Retyped here and hence typing mistake. Anyways... Some good points by you are probably genuine... But do you want me to explain what promises are in an answer. Also... Stackoverflow is a place for programmers to get help in problems... Biggest part of that would be helping them in understanding the mistake in their code... Not just how to fix it... And neither by providing a functionally pure, idiomatic scala solution. – sarveshseri Feb 08 '15 at 06:02
  • @dk and you probably have permission to edit my answer... So you could have done some fixing if you saw a mistake which wad obviously due to typing error... Instead of writing a huge comment. Anyways... Happy helping... :p – sarveshseri Feb 08 '15 at 06:04
  • @dk and iabout your thread.sleep issues.... incase you guys didn't read the highest voted answer... Go read it. – sarveshseri Feb 08 '15 at 06:07
  • 1)We read it and we're sorry about this highest voted answer - you can see highest voted comment by @Rich Henry there. 2)That's your second answer with `forEach` - so it's not just typo. 3) I can't just remove the whole unworking part from your answer (beginning from `Also...`) - as such edit may be rolled back by moderators. – dk14 Feb 08 '15 at 06:09
  • Again - do you understand that your solution with `promise` doesn't work?? – dk14 Feb 08 '15 at 06:16
  • Well... I am sorry for `forEach` mistakes.... these are because of my intense use of `Ramda.js` and its `forEach` function these days... my hands instinctively type `forEach` instead of `foreach`... And yes I realize that this Promise code will not work... Can you help me in fixing this without adding extra complexity ? – sarveshseri Feb 08 '15 at 06:17
  • just remove it - using promises is a bad solution here – dk14 Feb 08 '15 at 06:17
  • @dk14 about `@dk` lol... I guess 2 hours is not enough sleep... should sleep more... also typing without spects is not a good idea. – sarveshseri Feb 08 '15 at 06:21
  • @SarveshKumarSingh oh so you don't even see the clickable hint which appears right after you typed first letters - that's bad :) – dk14 Feb 08 '15 at 06:25
  • @dk14 ... it does not work most of the time... my browser has "issues" :D – sarveshseri Feb 08 '15 at 06:37