我试图了解来自 Java 背景的 Scala 期货:我知道你可以写:
val f = Future { ... }
那么我有两个问题:
- 这个未来是如何安排的?自动地?
- 它将使用什么调度程序?在 Java 中,您将使用可能是线程池等的执行程序。
此外,我怎样才能实现一个scheduledFuture
在特定时间延迟后执行的?谢谢
我试图了解来自 Java 背景的 Scala 期货:我知道你可以写:
val f = Future { ... }
那么我有两个问题:
此外,我怎样才能实现一个scheduledFuture
在特定时间延迟后执行的?谢谢
该Future { ... }
块是调用的语法糖Future.apply
(我相信您知道 Maciej),将代码块作为第一个参数传递。
查看此方法的文档,您可以看到它需要一个隐式ExecutionContext
- 正是这个上下文决定了它的执行方式。因此,要回答您的第二个问题,未来将由隐式范围内的任何 ExecutionContext 执行(当然,如果这是不明确的,这是一个编译时错误)。
在许多情况下,这将是 from import ExecutionContext.Implicits.global
,可以通过系统属性进行调整,但默认情况下使用ThreadPoolExecutor
每个处理器内核一个线程。
然而,调度是另一回事。对于某些用例,您可以提供自己ExecutionContext
的在执行前始终应用相同的延迟。但是,如果您希望延迟可以从呼叫站点控制,那么您当然不能使用Future.apply
,因为没有参数来传达应该如何安排。在这种情况下,我建议将任务直接提交给预定的执行者。
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
。