承诺是否有缺陷?

时间:2013-01-15 22:48:40

标签: scala future promise

this question的作者一样,我试图理解Scala 2.10期货和承诺中用户可见承诺的推理。

特别是,再次回到example from the 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会导致运行时异常的情况。因为承诺和生产者 - 未来是完全分离的,这意味着系统会挂起,消费者永远无法成功或失败。

所以使用promises的唯一安全方法需要像

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

这显然容易出错并且冗长。

我可以看到唯一一种可见的承诺类型 - future {}不足 - 是M. A. D.答案中的回调挂钩之一。但SIP的例子对我来说没有意义。

3 个答案:

答案 0 :(得分:7)

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

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

似乎没有必要再次抛出错误;你已经通过把它包装成答案来处理它,不是吗? (另请注意,如果produceSomething本身返回未来,则可以使用completeWith代替。)

答案 1 :(得分:4)

组合子

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

你需要Promise才能创建像这样的其他组合器。

调整回调

使用Promise为基于Future的API调整基于回调的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
  }
}

答案 2 :(得分:1)

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

promise.completeWith( future {
  r.produceSomething
})