如何在Scala中失败承诺

时间:2015-05-12 09:00:30

标签: scala promise future

在Scala文档中,有一个示例如何通过使用promises来选择更快成功的未来。

http://docs.scala-lang.org/overviews/core/futures.html#promises

def first[T](f: Future[T], g: Future[T]): Future[T] = {
  val p = promise[T]
  f onSuccess {
    case x => p.trySuccess(x)
  }
  g onSuccess {
    case x => p.trySuccess(x)
  }
  p.future
}

此函数返回首先成功的未来,如果其中任何一个失败,它将永远不会完成。

是否有可能以这样一种方式修改它,即使其他未来失败,如果它成功并且如果它们都成功则返回第二个,那么选择更快的一个就像代码现在一样。

4 个答案:

答案 0 :(得分:2)

您可以添加:

f onFailure {
  case e =>
    g onFailure {
      case _ =>
        p.failure(e)
    }
}

当两个期货都失败时,这将失败承诺与f相同的例外。您可以详细说明这一点,以创建一个例外,记录来自fg的2个例外情况。

答案 1 :(得分:1)

我建议你遵循Alvin Alexander关于Scala期货和承诺的建议here

我相信这是与期货合作的最佳方式

var courses = repository.GetAll();
var studentCourses = courses.Where(x => x.StudentCourses.StudentId == 1234);

答案 2 :(得分:0)

以下是选择最快未来或超时的基本模式,如果它们都太慢:

import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{ Success, Failure }
import akka.actor._
import akka.pattern.after

object GetFastestFutureOrTimeout extends App {
  val e = new TimeoutException("TimeoutException")
  val system = ActorSystem("GetFastestFutureOrTimeout")
  val f1 = Future { Thread.sleep(200); "this is f1" }
  val f2 = Future { Thread.sleep(100); "this is f2" }
  val timeoutFuture = after(500.milliseconds, using = system.scheduler) { Future.failed(e) }
  val f = Future.firstCompletedOf(f1 :: f2 :: timeoutFuture :: Nil)

  f onComplete {
    case Success(msg) => println(msg)
    case Failure(err) => println("An error occured: " + err.getMessage)
  }
}

这打印“这是f2”。如果timeoutFuture的超时更改为50,则会打印“发生错误:TimeoutException”。

在引擎盖下,firstCompletedOf使用Promise返回已完成的第一个Future的值,请参阅https://github.com/scala/scala/blob/v2.11.6/src/library/scala/concurrent/Future.scala#L503

答案 3 :(得分:0)

这是一个基本的实现,用于获取最快的成功响应或失败,如果它们都失败了:

def getFirstSuccessfulResultOrFail[T](requests: List[Future[T]]): Future[T] = {
  val p              = Promise[T]()
  val countDownLatch = AtomicInt(0)

  requests.foreach { f =>
    f.onComplete {
      case Failure(e) => if (countDownLatch.addAndGet(1) == requests.size) p.tryFailure(e)
      case Success(s) => p.trySuccess(s)
    }
  }

  p.future
}