Scala - 未来与并发

13

我正试图理解Scala中的future,而我来自Java背景:我了解到你可以这样写:

val f = Future {   ...    }

那我有两个问题:

  1. 这个定时器是如何被调度的?是自动的吗?
  2. 它将使用哪个调度程序?在Java中,您可以使用可作为线程池等的执行程序。

此外,我如何实现一个 scheduledFuture,即在特定时间延迟后执行的任务?谢谢


1
如果您想直接控制未来何时实现,应使用 Promise。 - Maurício Linhares
1
承诺(Promises)有点不同 - 从执行器的视角来看,它们本质上是一个Future(即一种只能写入一次值的容器,执行器必须在某个时刻插入值)。调用者/客户端没有直接使用Promise来控制调度的方法。 - Andrzej Doyle
2个回答

11
Future { ... } 块是对调用 Future.apply 的语法糖(正如您所知,Maciej),并将代码块作为第一个参数传递。
查看此方法的文档,您可以看到它需要一个隐式的 ExecutionContext - 这个上下文决定了它将如何执行。 因此,回答您的第二个问题,将由处于隐式范围内的任何 ExecutionContext 执行 future(当然,如果这是模棱两可的,则是编译时错误)。
在许多情况下,这将是从 import ExecutionContext.Implicits.global 导入的上下文,默认情况下使用带有每个处理器核心一个线程的 ThreadPoolExecutor,但可以通过系统属性进行调整。
然而,调度是另一回事。 对于某些用例,您可以提供自己的 ExecutionContext,始终在执行之前应用相同的延迟。 但是,如果您想要从调用站点控制延迟,那么您当然不能使用 Future.apply,因为没有参数来传达应该如何安排此操作。 在这种情况下,我建议直接将任务提交给计划的执行程序。

谢谢Andrzej,一如既往的乐于助人 :) - Bober02

3
Andrzej的答案已经涵盖了你问题的大部分内容。值得一提的是,Scala的“默认”隐式执行上下文(import scala.concurrent.ExecutionContext.Implicits._) 实际上就是一个 java.util.concurrent.Executor,整个ExecutionContext概念只是一个非常薄的封装,但与Java的executor框架密切相关。
如Mauricio所指出的,要实现类似于定时futures的功能,您将不得不使用promises和任何第三方调度机制。
没有将这种常见机制内置到Scala 2.10 futures中确实很遗憾,但并非致命。
Promise是异步计算的句柄。通过调用val p = Promise[Int]()来创建一个promise(假设范围内有 ExecutionContext)。我们承诺一个整数。
客户端可以通过调用仅依赖于承诺实现的未来p.future来抓取它,这只是一个Scala未来。
履行承诺只是简单地调用p.successful(3),此时未来将完成。
Play 2.x通过使用promises和一个普通的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

请注意,这比在代码中插入Thread.sleep(10000)要好得多,后者会阻塞线程并强制进行上下文切换。
此示例中还值得注意的是函数开头的val p = Promise...和结尾的p.future。这是使用Promise时的常见模式。这意味着该函数向客户端做出某些承诺,并启动异步计算以实现它。
有关Scala promises的更多信息,请在此处查看。请注意,它们使用来自concurrent包对象的小写future方法,而不是Future.apply。前者简单地委托给后者。个人而言,我更喜欢小写的future

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接