8

这是我之前的问题的后续

假设我想用我的函数创建一个未来,但不想立即启动它(即我不想调用val f = Future { ... // my function}.

现在我看到它可以按如下方式完成:

val p = 承诺[单位]
val f = p.future map { _ => // 我的函数在这里 }

这是用我的函数而不执行它来创建未来的唯一方法吗?

4

8 回答 8

7

你可以做这样的事情

val p = Promise[Unit]()
val f = p.future

//... some code run at a later time
p.success {
// your function
}

后期编辑:

我认为您正在寻找的模式可以这样封装:

class LatentComputation[T](f: => T) {
  private val p = Promise[T]()

  def trigger() { p.success(f) }

  def future: Future[T] = p.future
}

object LatentComputation {
  def apply[T](f: => T) = new LatentComputation(f)
}

你会像这样使用它:

val comp = LatentComputation {
// your code to be executed later
}

val f = comp.future

// somewhere else in the code
comp.trigger()
于 2013-05-15T21:32:20.910 回答
3

你总是可以用一个闭包来推迟创建,你不会马上得到未来的对象,但你会得到一个稍后调用的句柄。

type DeferredComputation[T,R] = T => Future[R]

def deferredCall[T,R](futureBody: T => R): DeferredComputation[T,R] =
  t => future {futureBody(t)}

def deferredResult[R](futureBody: => R): DeferredComputation[Unit,R] =
  _ => future {futureBody}
于 2013-05-16T06:52:54.223 回答
2

如果您对执行控制过于花哨,也许您应该改用演员?

或者,也许,您应该使用 aPromise而不是 a Future: aPromise可以传递给其他人,而您保留它以在以后“实现”它。

于 2013-05-15T22:21:27.407 回答
2

也值得一试Promise.completeWith

您已经知道如何使用p.future onComplete mystuff.

您可以使用p completeWith f.

于 2013-05-15T22:44:12.893 回答
2

您还可以定义一个创建并返回 Future 的函数,然后调用它:

val double = (value: Int) => {
  val f = Future { Thread.sleep(1000); value * 2 }
  f.onComplete(x => println(s"Future return: $x"))
  f
}

println("Before future.")
double(2)
println("After future is called, but as the future takes 1 sec to run, it will be printed before.")

我用它来执行 n 批次的期货,例如:

// The functions that returns the future.
val double = (i: Int) => {
  val future = Future ({
    println(s"Start task $i")
    Thread.sleep(1000)
    i * 2
  })

  future.onComplete(_ => {
    println(s"Task $i ended")
  })

  future
}

val numbers = 1 to 20

numbers
  .map(i => (i, double))
  .grouped(5)
  .foreach(batch => {
    val result = Await.result( Future.sequence(batch.map{ case (i, callback) => callback(i) }), 5.minutes )
    println(result)
  })
于 2019-08-02T21:47:22.003 回答
1

或者只是使用返回期货的常规方法,并使用诸如理解(顺序调用站点评估)之类的东西连续触发它们

于 2014-07-02T22:14:44.933 回答
1

这有点 hack,因为它与 future 的工作方式无关,但只需添加 lazy 就足够了: lazy val f = Future { ... // my function} 但请注意,这也是一种类型更改,因为每当您引用它时,您都需要声明引用也懒惰,否则它将被执行。

于 2018-08-02T07:33:53.740 回答
1

标准库 Future 的这个众所周知的问题:它们的设计方式使得它们在引用上不透明,因为它们急切地评估并记住他们的结果。在大多数用例中,这完全没问题,Scala 开发人员很少需要创建未评估的未来。

采取以下程序:

val x = Future(...); f(x, x) 

不是同一个程序

f(Future(...), Future(...))

因为在第一种情况下,未来被评估一次,在第二种情况下,它被评估两次。

这些库提供了必要的抽象来处理引用透明的异步任务,除非开发人员明确要求,否则这些任务的评估被推迟并且不会被记忆。

  1. 斯卡拉兹任务
  2. Monix 任务
  3. fs2

如果您想使用 Cats,Cats 效果可以很好地与 Monix 和 fs2 配合使用。

于 2018-02-26T11:09:01.780 回答