为什么未来的例子不起作用?

时间:2014-08-11 05:05:00

标签: scala akka future

我正在阅读akkaScala文档,有一个例子(第171页)

// imports added for compilation
import scala.concurrent.{ExecutionContext, Future}
import ExecutionContext.Implicits.global

class Some {
}

object Some {
    def main(args: Array[String]) {
        // Create a sequence of Futures
        val futures = for (i <- 1 to 1000) yield Future(i * 2)
        val futureSum = Future.fold(futures)(0)(_ + _)
        futureSum foreach println        
    }
}

我跑了,但什么都没发生。我的意思是控制台输出没有任何东西。有什么问题?

3 个答案:

答案 0 :(得分:4)

您不会等待将来完成,因此您在退出程序和完成期货以及副作用运行之间创建竞赛。在你的机器上,未来似乎在竞争者中失去了竞争对手。谁说&#34;它的作用&#34;,未来正在赢得比赛。

您可以使用Await阻止未来并等待它完成。这是你应该只做的事情&#34;在世界末日&#34;,你应该很少真正使用Await ......

// imports added for compilation
import scala.concurrent.{ExecutionContext, Future}
import ExecutionContext.Implicits.global
import scala.concurrent.duration._   // for the "1 second" syntax
import scala.concurrent.Await        

class Some {
}

object Some {
    def main(args: Array[String]) {
        // Create a sequence of Futures
        val futures = for (i <- 1 to 1000) yield Future(i * 2)
        val futureSum = Future.fold(futures)(0)(_ + _)
        // we map instead of foreach, to make sure that the side-effect is part of the future
        // and we "await" for the future to complete (for 1 second)
        Await.result(futureSum map println, 1 second)
    }
}

答案 1 :(得分:1)

正如其他人所说,问题是竞争条件,即期货与计划终止竞争。 JVM具有守护程序线程的概念。它等待非守护程序线程终止但不等待守护程序线程。因此,如果您想等待线程完成,请使用非守护程序线程。

为scala future创建线程的方式是使用隐式scala.concurrent.ExecutionContext。您使用的那个(import ExecutionContext.Implicits.global)启动守护程序线程。但是,可以使用非守护程序线程。因此,如果您使用带有非守护程序线程的ExecutionContext,它将等待,在您的情况下,这是合理的行为。天真地:

import scala.concurrent.Future
import scala.concurrent.ExecutionContextExecutor
import scala.concurrent.ExecutionContext

class MyExecutionContext extends ExecutionContext {
  override def execute(runnable:Runnable) = {
    val t = new Thread(runnable)
    t.setDaemon(false)
    t.start()
  }
  override def reportFailure(t:Throwable) = t.printStackTrace
}

object Some {
   implicit lazy val context: ExecutionContext = new MyExecutionContext

    def main(args: Array[String]) {
        // Create a sequence of Futures
        val futures = for (i <- 1 to 1000) yield Future(i * 2)
        val futureSum = Future.fold(futures)(0)(_ + _)
        futureSum foreach println        
    }
}

在生产中使用上述ExecutionContext时要小心,因为它没有使用线程池并且可以创建无界线程,但消息是:您可以通过ExecutionContext控制Futures背后的线程的所有内容。探索各种scala和akka语境,找到你需要的东西,或者如果没有什么适合的话,你可以自己编写。

答案 2 :(得分:0)

主要功能结束时的以下两个陈述都有助于您的需要。正如上面的答案所说,允许未来完成。主线程与Future线程不同,主要完成后,它会在Future thread之前终止。

  1. Thread.sleep(500)// ...简单解决方案

  2. Await.result(futureSum,Duration(500,MILLISECONDS))//...导入scala.concurrent.duration._以使用Duration对象。