private class FutMemorizer[T](valid: T => Boolean)(f: () => Future[T]) {
private val ref = new AtomicReference[Promise[T]]
@scala.annotation.tailrec
final def get(): Future[T] = {
val nullableRef = ref.get()
val valid = checkPromise(ref.get())
if(valid) {
nullableRef.future
} else {
val p = Promise[T]
val success = ref.compareAndSet(nullableRef, p)
if(success) {
p.completeWith(f())
p.future
} else {
get()
}
}
}
private def checkPromise(nullable: Promise[T]) = {
nullable != null && {
nullable.future.value match {
case None => true // future is not complete all caller should wait
case Some(Success(v)) => valid(v)
case _ => false
}
}
}
}
我正在实施一个Future
存储器,只能缓存valid
未来值。
必须符合以下要求
由
Futures
创建的f
从未执行并行- 醇>
get
永远不会返回无效值(一旦invalid
召回f()
重新加载)
我的实施是否正确?
是否有更多functional
或更简单的方法来执行此操作(因为我几乎不能证明mime的正确性)?
答案 0 :(得分:0)
据我所知,这是错误的:
p.completeWith(f())
调用者获得的未来的值是{或者有时会是f()
返回的未来的值,但是在该值满足或将满足valid(...)
的任何地方都不会被检查;如果需要时间,f()
返回的结果未来正在进行中的其他呼叫者也是如此。只有当f()
的结果完成时,下一个调用者才可能开始“修复”它。
我可能会通过以下方式解决此问题(请参阅fixed
方法),并进行一些风格更改:
class FutMemorizer[T](valid: T => Boolean)(f: () => Future[T]) {
private val ref = new AtomicReference[Future[T]]
@tailrec
final def get: Future[T] = {
val current = ref.get
if (current != null && isValid(current)) current
else {
val p = Promise[T]
val pf = p.future
if (ref.compareAndSet(current, pf)) {
p.completeWith(fixed(f))
pf
} else get
}
}
private def fixed(f: () => Future[T]): Future[T] =
f() flatMap { t =>
if (valid(t)) Future.successful(t) else fixed(f)
}
private def isValid(future: Future[T]) =
future.value match {
case None => true // future is not complete all caller should wait
case Some(Success(v)) => valid(v)
case _ => false
}
}
至于你关于更实用的方法的问题,我猜测 f
和valid
对外部状态产生影响并将其计算基于它(我是猜测是否存在失效的存储器会严重阻碍它。
答案 1 :(得分:0)
找到spray-cache已经有此功能