5

就像这个问题的作者一样,我试图理解 Scala 2.10 的期货和承诺中用户可见承诺的推理。

特别是,再次回到SIP 中的示例,它是否完全有缺陷:

import scala.concurrent.{ future, promise }
val p = promise[T]
val f = p.future
val producer = future {
  val r = produceSomething()
  p success r
  continueDoingSomethingUnrelated()
}
val consumer = future {
  startDoingSomething()
  f onSuccess {
    case r => doSomethingWithResult()
  }
}

我在想象调用produceSomething导致运行时异常的情况。因为 promise 和 producer-future 完全分离,这意味着系统挂起,消费者永远不会成功或失败。

因此,使用 Promise 的唯一安全方法需要类似

val producer = future {
  try {
    val r.produceSomething()
    p success r
  } catch {
     case e: Throwable =>
       p failure e
       throw e  // ouch
  }
  continueDoingSomethingUnrelated()
}

这显然容易出错且冗长。

对于可见的 Promise 类型,我能看到的唯一情况future {}(不足之处)是 MAD 答案中的回调钩子之一。但是 SIP 的例子对我来说没有意义。

4

3 回答 3

7

这就是您很少使用的原因successfailure除非您已经知道某些东西是防弹的。如果你想要防弹,这就是Try

val producer = future {
  p complete Try( produceSomething )
  continueDoingSomethingUnrelated()
}

似乎没有必要再次抛出错误;您已经通过将其打包到承诺的答案中来处理它,不是吗?(另外,请注意,如果produceSomething它本身返回一个未来,你可以使用它completeWith来代替。)

于 2013-01-15T23:05:40.430 回答
4

组合器

您可以使用Promise构建Future库中尚未包含的其他组合器。

  • “选择”关掉第一个满足的未来。结果返回,其余的期货作为一个序列:https ://gist.github.com/viktorklang/4488970 。

  • 一种after返回Future在一段时间后完成的方法,以“超时”未来:https ://gist.github.com/3804710 。

你需要 Promises 才能像这样创建其他组合子。

调整回调

用于Promise使基于回调的 API 适应基于回调Future的 API。例如:

def retrieveThing(key: String): Future[Thing] = {
  val p = Promise[Thing]()

  val callback = new Callback() {
    def receive(message: ThingMessage) {
      message.getPayload match {
        case t: Thing =>
          p success t        
        case err: SystemErrorPayload =>
          p failure new Exception(err.getMessage)
      }
    }
  }

  thingLoader.load(key, callback, timeout)
  p.future
}

同步器

使用 构建同步器Promise。例如,为昂贵的操作返回一个缓存值,或者计算它,但不要为同一个键计算两次:

private val cache = new ConcurrentHashMap[String, Promise[T]]

def getEntry(key: String): Future[T] = {
  val newPromise = Promise[T]()
  val foundPromise = cache putIfAbsent (key, newPromise)

  if (foundPromise == null) {
    newPromise completeWith getExpensive(key)
    newPromise.future
  } else {
    foundPromise.future
  }
}
于 2013-01-16T00:28:13.717 回答
1

Promise 有一个 completeWith(f: Future) 方法,可以通过自动处理成功/失败场景来解决这个问题。

promise.completeWith( future {
  r.produceSomething
})
于 2013-01-15T23:15:38.330 回答