Последовательно объедините произвольное количество фьючерсов в Scala
Я новичок в scala, и я пытаюсь объединить несколько фьючерсов в scala 2.10RC3. Futures
должен выполняться в последовательном порядке. В документе Scala SIP14 метод andThen
определяется для выполнения фьючерсов в последовательном порядке. Я использовал этот метод для объединения нескольких Futures
(см. Пример ниже). Я ожидал, что он напечатает 6
, но на самом деле результат 0
. Что я здесь делаю неправильно? У меня есть два вопроса:
Во-первых, почему результат 0
. Во-вторых, как я могу объединить несколько Futures
, так что выполнение второго Future
не запускается до того, как будет завершено первое Future
.
val intList = List(1, 2, 3)
val sumOfIntFuture = intList.foldLeft(Future { 0 }) {
case (future, i) => future andThen {
case Success(result) => result + i
case Failure(e) => println(e)
}
}
sumOfIntFuture onSuccess { case x => println(x) }
Ответы
Ответ 1
andThen
- для побочных эффектов. Он позволяет указать некоторые действия, которые необходимо выполнить после завершения будущего, и до того, как он будет использован для чего-то еще.
Использование карты:
scala> List(1, 2, 3).foldLeft(Future { 0 }) {
| case (future, i) => future map { _ + i }
| } onSuccess { case x => println(x) }
6
Ответ 2
Мне нравится этот общий подход:
trait FutureImplicits {
class SeriallyPimp[T, V](futures: Seq[T]) {
def serially(f: T => Future[V])(implicit ec: ExecutionContext): Future[Seq[V]] = {
val buf = ListBuffer.empty[V]
buf.sizeHint(futures.size)
futures.foldLeft(Future.successful(buf)) { (previousFuture, next) =>
for {
previousResults <- previousFuture
nextResult <- f(next)
} yield previousResults += nextResult
}
}
}
implicit def toSeriallyPimp[T, V](xs: Seq[T]): SeriallyPimp[T, V] =
new SeriallyPimp(xs)
}
Затем смешайте приведенную выше черту и используйте ее следующим образом:
val elems: Seq[Elem] = ???
val save: Elem => Future[Result] = ???
val f: Future[Seq[Result]] = elems serially save
Этот код можно улучшить, чтобы сохранить тип входной коллекции. См. эту статью.