13

我试图了解来自 Java 背景的 Scala 期货:我知道你可以写:

val f = Future {   ...    }

那么我有两个问题:

  1. 这个未来是如何安排的?自动地?
  2. 它将使用什么调度程序?在 Java 中,您将使用可能是线程池等的执行程序。

此外,我怎样才能实现一个scheduledFuture在特定时间延迟后执行的?谢谢

4

2 回答 2

11

Future { ... }块是调用的语法糖Future.apply(我相信您知道 Maciej),将代码块作为第一个参数传递。

查看此方法的文档,您可以看到它需要一个隐式ExecutionContext- 正是这个上下文决定了它的执行方式。因此,要回答您的第二个问题,未来将由隐式范围内的任何 ExecutionContext 执行(当然,如果这是不明确的,这是一个编译时错误)。

在许多情况下,这将是 from import ExecutionContext.Implicits.global,可以通过系统属性进行调整,但默认情况下使用ThreadPoolExecutor每个处理器内核一个线程。

然而,调度是另一回事。对于某些用例,您可以提供自己ExecutionContext的在执行前始终应用相同的延迟。但是,如果您希望延迟可以从呼叫站点控制,那么您当然不能使用Future.apply,因为没有参数来传达应该如何安排。在这种情况下,我建议将任务直接提交给预定的执行者。

于 2013-05-03T11:35:29.443 回答
3

Andrzej 的回答已经涵盖了您问题的大部分内容。值得一提的是,Scala 的“默认”隐import scala.concurrent.ExecutionContext.Implicits._执行上下文java.util.concurrent.Executor

正如 Mauricio 指出的那样,为了实现类似于预定期货的东西,您将不得不使用 Promise 和任何第三方调度机制。

遗憾的是,Scala 2.10 期货中没有为此内置的通用机制,但也不是致命的。

Promise 是异步计算的句柄。ExecutionContext您通过调用创建一个(假设在范围内) val p = Promise[Int]()。我们只是承诺了一个整数。
客户可以通过调用 来获取依赖于承诺的未来p.future,这只是一个 Scala 未来。
履行一个承诺只是一个调用的问题p.successful(3),此时未来将完成。

Play 2.x 通过使用 Promise 和一个普通的 Java 1.4 计时器来解决调度问题。
是指向源的防链接腐烂链接。

我们也来看看这里的源码:

object Promise {
  private val timer = new java.util.Timer()

  def timeout[A](message: => A, duration: Long, unit: TimeUnit = TimeUnit.MILLISECONDS)
                (implicit ec: ExecutionContext): Future[A] = {
    val p = Promise[A]()
    timer.schedule(new java.util.TimerTask {
      def run() {
        p.completeWith(Future(message)(ec))
      }
    }, unit.toMillis(duration))
    p.future
  }
}

然后可以像这样使用它:

val future3 = Promise.timeout(3, 10000) // will complete after 10 seconds

请注意,这比将 a 插入您的代码要好得多Thread.sleep(10000),后者会阻塞您的线程并强制进行上下文切换。

在此示例中还值得注意的是val p = Promise...函数的开头和p.future结尾处的 。这是使用 Promise 时的常见模式。意思是这个函数向客户端做出了一些承诺,并启动了一个异步计算以实现它。

在这里查看有关 Scala 承诺的更多信息。请注意,他们使用包对象中的小写future方法concurrent而不是Future.apply. 前者只是委托给后者。就个人而言,我更喜欢小写字母future

于 2013-05-04T01:59:04.950 回答