我试图了解来自Java背景的Scala期货:我知道你可以写:
val f = Future { ... }
然后我有两个问题:
此外,如何实现scheduledFuture
,即在特定时间延迟后执行的{{1}}?感谢
答案 0 :(得分:11)
Future { ... }
块是调用Future.apply
的语法糖(因为我确定你知道Maciej),传递代码块作为第一个参数。
查看docs for this method,您可以看到它需要一个隐式ExecutionContext
- 正是这个上下文决定了它的执行方式。因此,为了回答你的第二个问题,未来将由隐式作用域中的ExecutionContext执行(当然,如果这是不明确的,则是编译时错误)。
在许多情况下,这将是import ExecutionContext.Implicits.global
中的一个,可以通过系统属性进行调整,但默认情况下使用ThreadPoolExecutor
,每个处理器核心有一个线程。
然而,调度是另一回事。对于某些用例,您可以提供自己的ExecutionContext
,它们在执行前始终应用相同的延迟。但是,如果您希望延迟可以从呼叫站点进行控制,那么您当然不能使用Future.apply
,因为没有参数可以告知如何安排此延迟。在这种情况下,我建议将任务直接提交给预定的执行者。
答案 1 :(得分:3)
Andrzej的回答已经涵盖了你问题的大部分内容。值得一提的是,Scala的“默认”隐式执行上下文(import scala.concurrent.ExecutionContext.Implicits._
)字面上一个java.util.concurrent.Executor
,整个ExecutionContext概念是一个非常薄的包装器,但是与它紧密对齐Java的执行者框架。
为了实现类似于预定期货的东西,正如Mauricio指出的那样,你将不得不使用承诺和任何第三方调度机制。
没有一个共同的机制,这内置Scala 2.10期货是一个遗憾,但没有什么致命的。
promise是异步计算的句柄。您可以通过调用ExecutionContext
创建一个(假设范围为val p = Promise[Int]()
)。我们只承诺了一个整数
客户可以通过调用p.future
来获取取决于履行承诺的未来,这只是Scala的未来。
履行承诺只需要致电p.successful(3)
,此时未来将完成。
播放2.x通过使用promises和普通的旧Java 1.4 Timer来解决调度问题 Here是指向源代码的链接防范链接。
让我们来看看这里的来源:
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
请注意,这比将Thread.sleep(10000)
插入代码要好得多,这会阻塞您的线程并强制进行上下文切换。
此示例中值得注意的是函数开头的val p = Promise...
和结尾的p.future
。这是使用promises时的常见模式。这意味着这个函数对客户端做出了一些承诺,并启动异步计算以实现它。
有关Scala承诺的更多信息,请查看here。请注意,他们使用future
包对象中的小写concurrent
方法而不是Future.apply
。前者只是委托后者。就个人而言,我更喜欢小写future
。