如何将结果 Future[ Option[ T ] ] 组合成 Seq[ T ]
how to combine the results Future[ Option[ T ] ] into Seq[ T ]
我有一个方法
def readTree(id: String): Future[Option[CategoryTreeResponse]]
和字符串列表 channels:List[String]
。
如何将所有结果迭代组合成一个非Future Sequence?如:
def readAllTrees(): Seq[CategoryTreeResponse] = ???
可能没有阻塞。
来自命令式世界,我会这样做:
import scala.concurrent.duration._
def readTrees(): Seq[CategoryTreeResponse] = {
val list = ListBuffer[CategoryTreeResponse]()
for (id <- channels) {
val tree = Await.result(readTree(id), 5.seconds)
if (tree.isDefined) {
list += tree.get
}
}
list
}
你可以这样做
def readAllTrees(channels: List[String]): Future[Seq[CategoryTreeResponse]] = {
Future.sequence(channels.map(readTree(_))).map(_.flatten)
}
我已经更改了 readAllTrees 的签名以接收列表和 return 序列的未来。
如果您想访问生成的序列,您需要等到完成
Await.result(readAllTrees(channels), Duration.Inf)
但这不是管理期货的好方法,因为它会锁定调用 Await.ready
的线程
Future.sequence 和 Await.result 应该有帮助。不过我同意 Mikel 的观点,最好使用 Future class
的 map/flatMap/foreach 等方法尽可能长时间地保持异步
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
case class CategoryTreeResponse()
val futureResults: List[Future[Option[CategoryTreeResponse]]] = List(
Future.successful(Option(CategoryTreeResponse())),
Future.successful(Option(CategoryTreeResponse())),
Future.successful(None)
)
val futureResult: Future[List[Option[CategoryTreeResponse]]] = Future.sequence(futureResults)
val allResults: List[Option[CategoryTreeResponse]] = Await.result(futureResult, Duration.Inf)
val nonEmptyResults: Seq[CategoryTreeResponse] = allResults.flatMap(_.toSeq)
// Exiting paste mode, now interpreting.
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
defined class CategoryTreeResponse
futureResults: List[scala.concurrent.Future[Option[CategoryTreeResponse]]] = List(Future(Success(Some(CategoryTreeResponse()))), Future(Success(Some(CategoryTreeResponse()))), Future(Success(None)))
futureResult: scala.concurrent.Future[List[Option[CategoryTreeResponse]]] = Future(Success(List(Some(CategoryTreeResponse()), Some(CategoryTreeResponse()), None)))
allResults: List[Option[CategoryTreeResponse]] = List(Some(CategoryTreeResponse()), Some(CategoryTreeResponse()), None)
nonEmptyResults: Seq[CategoryTreeResponse] = List(CategoryTreeResponse(), CategoryTreeResponse())
scala>
我有一个方法
def readTree(id: String): Future[Option[CategoryTreeResponse]]
和字符串列表 channels:List[String]
。
如何将所有结果迭代组合成一个非Future Sequence?如:
def readAllTrees(): Seq[CategoryTreeResponse] = ???
可能没有阻塞。
来自命令式世界,我会这样做:
import scala.concurrent.duration._
def readTrees(): Seq[CategoryTreeResponse] = {
val list = ListBuffer[CategoryTreeResponse]()
for (id <- channels) {
val tree = Await.result(readTree(id), 5.seconds)
if (tree.isDefined) {
list += tree.get
}
}
list
}
你可以这样做
def readAllTrees(channels: List[String]): Future[Seq[CategoryTreeResponse]] = {
Future.sequence(channels.map(readTree(_))).map(_.flatten)
}
我已经更改了 readAllTrees 的签名以接收列表和 return 序列的未来。
如果您想访问生成的序列,您需要等到完成
Await.result(readAllTrees(channels), Duration.Inf)
但这不是管理期货的好方法,因为它会锁定调用 Await.ready
的线程Future.sequence 和 Await.result 应该有帮助。不过我同意 Mikel 的观点,最好使用 Future class
的 map/flatMap/foreach 等方法尽可能长时间地保持异步scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
case class CategoryTreeResponse()
val futureResults: List[Future[Option[CategoryTreeResponse]]] = List(
Future.successful(Option(CategoryTreeResponse())),
Future.successful(Option(CategoryTreeResponse())),
Future.successful(None)
)
val futureResult: Future[List[Option[CategoryTreeResponse]]] = Future.sequence(futureResults)
val allResults: List[Option[CategoryTreeResponse]] = Await.result(futureResult, Duration.Inf)
val nonEmptyResults: Seq[CategoryTreeResponse] = allResults.flatMap(_.toSeq)
// Exiting paste mode, now interpreting.
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
defined class CategoryTreeResponse
futureResults: List[scala.concurrent.Future[Option[CategoryTreeResponse]]] = List(Future(Success(Some(CategoryTreeResponse()))), Future(Success(Some(CategoryTreeResponse()))), Future(Success(None)))
futureResult: scala.concurrent.Future[List[Option[CategoryTreeResponse]]] = Future(Success(List(Some(CategoryTreeResponse()), Some(CategoryTreeResponse()), None)))
allResults: List[Option[CategoryTreeResponse]] = List(Some(CategoryTreeResponse()), Some(CategoryTreeResponse()), None)
nonEmptyResults: Seq[CategoryTreeResponse] = List(CategoryTreeResponse(), CategoryTreeResponse())
scala>