与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的例子对我来说没有意义。
答案 0 :(得分:7)
这就是为什么你很少使用success
和failure
,除非你已经知道某些东西是防弹的。如果您想要防弹,这就是Try
的用途:
val producer = future {
p complete Try( produceSomething )
continueDoingSomethingUnrelated()
}
似乎没有必要再次抛出错误;你已经通过把它包装成答案来处理它,不是吗? (另请注意,如果produceSomething
本身返回未来,则可以使用completeWith
代替。)
答案 1 :(得分:4)
您可以使用Promise
构建库中尚未包含的其他Future
个组合器。
“选择”关闭第一个未来。返回结果,剩余的期货作为序列:https://gist.github.com/viktorklang/4488970。
after
方法,返回在一段时间后完成的Future
,以“超时”未来:https://gist.github.com/3804710。
你需要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
})