6

没有 Future,这就是我如何将所有较小的 Seq 组合成一个带有平面图的大 Seq

category.getCategoryUrlKey(id: Int):Seq[Meta] // main method
val appDomains: Seq[Int]

val categories:Seq[Meta] = appDomains.flatMap(category.getCategoryUrlKey(_))

现在该方法getCategoryUrlKey可能会失败。我在前面放了一个断路器,以避免在大量maxFailures之后为下一个元素调用它。现在断路器不返回 aSeq而是返回 aFuture[Seq]

lazy val breaker = new akka.pattern.CircuitBreaker(...)

private def getMeta(appDomainId: Int): Future[Seq[Meta]] = {
  breaker.withCircuitBreaker {
    category.getCategoryUrlKey(appDomainId)
  }
}

如何遍历 ListappDomains并将结果组合成一个 Future[Seq] ,可能成为 Seq ?

如果函数式编程适用,有没有办法在没有临时变量的情况下直接转换?

4

3 回答 3

6

使用 Future.sequence 压缩期货序列

Future.sequence转换Seq[Future[T]]Future[Seq[T]]

在你的情况下TSeq. 在序列操作之后,您将得到 Seq[Seq[T]]。因此,只需在使用 flatten 进行序列操作后将其展平即可。

def squashFutures[T](list: Seq[Future[Seq[T]]]): Future[Seq[T]] =
  Future.sequence(list).map(_.flatten)

你的代码变成

Future.sequence(appDomains.map(getMeta)).map(_.flatten)
于 2017-06-16T09:45:09.447 回答
1

从 TraversableOnce[Future[A]] 到 Future[TraversableOnce[A]]

val categories = Future.successful(appDomains).flatMap(seq => {
    val fs = seq.map(i => getMeta(i))
    val sequenced = Future.sequence(fs)
    sequenced.map(_.flatten)
})
  • Future.successful(appDomains)提升appDomains到上下文中Future

希望这可以帮助。

于 2017-06-16T09:53:05.520 回答
0
val metaSeqFutureSeq = appDomains.map(i => getMeta(i))
// Seq[Future[Seq[Meta]]]

val metaSeqSeqFuture = Future.sequence(metaSeqFutureSeq)
// Future[Seq[Seq[Meta]]]
// NOTE :: this future will fail if any of the futures in the sequence fails

val metaSeqFuture = metaSeqSeqFuture.map(seq => seq.flatten)
// Future[Seq[Meta]]

如果您想拒绝唯一失败的未来,但保留成功的未来,那么我们将不得不有点创意,并使用承诺来建立我们的未来。

import java.util.concurrent.locks.ReentrantLock

import scala.collection.mutable.ArrayBuffer
import scala.concurrent.{Future, Promise}
import scala.util.{Failure, Success}

def futureSeqToOptionSeqFuture[T](futureSeq: Seq[Future[T]]): Future[Seq[Option[T]]] = {
  val promise = Promise[Seq[Option[T]]]()

  var remaining = futureSeq.length

  val result = ArrayBuffer[Option[T]]()
  result ++ futureSeq.map(_ => None)

  val resultLock = new ReentrantLock()

  def handleFutureResult(option: Option[T], index: Int): Unit = {
    resultLock.lock()
    result(index) = option
    remaining = remaining - 1
    if (remaining == 0) {
      promise.success(result)
    }
    resultLock.unlock()
  }

  futureSeq.zipWithIndex.foreach({ case (future, index) => future.onComplete({
    case Success(t) => handleFutureResult(Some(t), index)
    case Failure(ex) => handleFutureResult(None, index)
  }) })

  promise.future
}

val metaSeqFutureSeq = appDomains.map(i => getMeta(i))
// Seq[Future[Seq[Meta]]]

val metaSeqOptionSeqFuture = futureSeqToOptionSeqFuture(metaSeqFutureSeq)
// Future[Seq[Option[Seq[Meta]]]]

val metaSeqFuture = metaSeqSeqFuture.map(seq => seq.flatten.flatten)
// Future[Seq[Meta]]
于 2017-06-16T11:11:37.737 回答