将多个 Future[Seq] 连接成一个 Future[Seq]
Concatenate many Future[Seq] into one Future[Seq]
没有 Future,这就是我如何将所有较小的 Seq 组合成一个带有 flatmap
的大 Seq
category.getCategoryUrlKey(id: Int):Seq[Meta] // main method
val appDomains: Seq[Int]
val categories:Seq[Meta] = appDomains.flatMap(category.getCategoryUrlKey(_))
现在方法 getCategoryUrlKey
可能会失败。我在前面放了一个断路器,以避免在 maxFailures 之后为下一个元素调用它。现在断路器不是 return Seq
而是 Future[Seq]
lazy val breaker = new akka.pattern.CircuitBreaker(...)
private def getMeta(appDomainId: Int): Future[Seq[Meta]] = {
breaker.withCircuitBreaker {
category.getCategoryUrlKey(appDomainId)
}
}
如何遍历列表 appDomains
并将结果组合成一个单一的 Future[Seq] ,可能成为 Seq ?
如果适用函数式编程,有没有不用临时变量直接转换的方法?
使用 Future.sequence
压缩期货序列
Future.sequence
将Seq[Future[T]]
转换为Future[Seq[T]]
在你的例子中 T
是 Seq
。在序列操作之后,你将得到 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)
从 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
的上下文中
希望对您有所帮助。
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]]
没有 Future,这就是我如何将所有较小的 Seq 组合成一个带有 flatmap
的大 Seqcategory.getCategoryUrlKey(id: Int):Seq[Meta] // main method
val appDomains: Seq[Int]
val categories:Seq[Meta] = appDomains.flatMap(category.getCategoryUrlKey(_))
现在方法 getCategoryUrlKey
可能会失败。我在前面放了一个断路器,以避免在 maxFailures 之后为下一个元素调用它。现在断路器不是 return Seq
而是 Future[Seq]
lazy val breaker = new akka.pattern.CircuitBreaker(...)
private def getMeta(appDomainId: Int): Future[Seq[Meta]] = {
breaker.withCircuitBreaker {
category.getCategoryUrlKey(appDomainId)
}
}
如何遍历列表 appDomains
并将结果组合成一个单一的 Future[Seq] ,可能成为 Seq ?
如果适用函数式编程,有没有不用临时变量直接转换的方法?
使用 Future.sequence
压缩期货序列Future.sequence
将Seq[Future[T]]
转换为Future[Seq[T]]
在你的例子中 T
是 Seq
。在序列操作之后,你将得到 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)
从 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
的上下文中
希望对您有所帮助。
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]]