Scala - 期货和并发

时间:2013-05-03 11:12:00

标签: scala concurrency promise scheduling future

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

val f = Future {   ...    }

然后我有两个问题:

  1. 这个未来如何安排?自动?
  2. 它会使用什么样的调度程序?在Java中,您将使用可能是线程池等的执行程序。
  3. 此外,如何实现scheduledFuture,即在特定时间延迟后执行的{{1}}?感谢

2 个答案:

答案 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