9

我试图在新的 Scala 2.10期货功能上重现该示例。我使用的代码是:

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")
    }
}

而不是打印:

Test print before future
Hello future!
Test print after future

它只是打印:

Test print before future
Test print after future

知道为什么我有这种行为吗?我的 scala 编译器版本是 2.10.0-20120507。

4

3 回答 3

30

问题是您将其作为独立程序执行,其主线程在其中一个工作线程可以执行“Hello future!”之前终止。println. (新的期货库产生的线程是守护线程)。

您还可以使用Await对象(也在 中scala.concurrent)等到未来f完成:

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

这可以打印:

Test print before future
Test print after future
Hello future!

或者,它可以打印“Hello future!” 在“未来之后的测试打印”之前,具体取决于线程调度。

同样,您可以强制主线程等到f最后一个完成之前println,如下所示:

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")
  }
}

哪个会打印:

Test print before future
Hello future!
Test print after future

但是,请注意,当您使用 时Await,您是在阻塞。这当然可以确保您的主应用程序线程不会终止,但除非另有必要,否则通常不应使用。

Await对于此类情况,该对象是必要的逃生舱口,但在整个应用程序代码中使用它而不考虑其语义可能会导致更慢、更少并行执行。例如,如果您需要确保回调以某些指定的顺序执行, ,还有其他替代方法,例如andThenmap上的方法Future。)

于 2012-05-12T19:03:15.623 回答
1

我认为这里的问题是时机。您未来的代码很可能在单独的守护线程中运行。我认为应用程序完成得非常快,并且这个守护线程没有足够的时间来正确执行(应用程序不会等待守护线程完成)。但这也是非常依赖系统的行为。对我来说,它打印:

Test print before future
Test print after future
Hello future!

然后退出(我使用的是 Scala 2.10.0-M3)。您可以尝试以下以对其进行测试 - 只需将主执行线程置于睡眠状态几秒钟,然后查看是否Hello future!打印:

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.")
    }
}
于 2012-05-12T18:06:02.050 回答
1

我只想补充一点,一般来说,期货没有运行的另一种可能性是:达到线程池限制。

在您的情况下,正如其他人所指出的那样,这可能只是一个时间问题,但作为未来参考,请考虑以下示例:

import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration


object FutureDebug {
  def main( args: Array[String] ) {

    for (i <- Range(0, 4)) {
      future {
        while (true) {
          Thread.sleep(1000)
          println("I'm doing stupid things in a future")
        }
      }
    }

    println("(1) reached? yes")
    val fut = future {
      for (i <- Range(0, 1000)) {
        println("never reached " + i)
      }
      3.14
    }    
    println("(2) reached? yes")
    Await.result(fut, Duration.Inf)
    println("(3) reached? no")
  }
}

在我的机器上,默认的全局执行上下文只有 4 个线程。由于工作线程忙于执行 4 个无意义的 future,因此下面的 future 将永远不会运行。这就是为什么人们应该小心默认执行上下文,并且在处理多个(真正)长时间运行的期货时最好指定自己的执行上下文。

于 2014-04-27T14:33:19.150 回答