Как выполнить список фьючерсов Scala последовательно - PullRequest
1 голос
/ 21 июня 2019

Я хочу выполнить Список функций, который возвращает фьючерсы последовательно.

Какие могут быть возможные реализации для следующего метода:

def runSequentially[A, B](lazyFutures: List[A ⇒ Future[B]])(input: A)
(implicit ec: ExecututionContext): Future[List[B]]

Тест

test("execute futures sequentially") {
    import scala.concurrent.ExecutionContext.Implicits.global

    def runSequentially[A, B](lazyFutures: List[A ⇒ Future[B]])(input: A): Future[List[B]] = ???

    val l: List[Unit ⇒ Future[Unit]] = List(
      _ ⇒ Future { Thread.sleep(1000); println(1) },
      _ ⇒ Future { Thread.sleep(5000); println(2) },
      _ ⇒ Future { Thread.sleep(500); println(3) }
    )

    Await.result(runSequentially(l)(5), 20.seconds)

  }

Это должно вывести:

1
2
3

Ответы [ 4 ]

4 голосов
/ 21 июня 2019

Попробуйте создать пул с одним потоком и используйте Future.traverse примерно так

val singleThreadPool = Executors.newFixedThreadPool(1, (r: Runnable) => new Thread(r, s"single-thread-pool"))
implicit val singleThreadEc = ExecutionContext.fromExecutor(singleThreadPool)

def runSequentially[A, B](lazyFutures: List[A ⇒ Future[B]])(input: A): Future[List[B]] =
  Future.traverse(lazyFutures)(f => f(input))
2 голосов
/ 21 июня 2019

Вы также можете использовать cats и Kleisli

import scala.concurrent.ExecutionContext.Implicits.global
import cats.implicits._
import cats.data.Kleisli

def runSequentially[A, B](lazyFutures: List[A ⇒ Future[B]])(input: A) : Future[List[B]] = lazyFutures
    .map(Kleisli.apply) //List[Kleisli[Future, A, B]]
    .sequence           //Kleisli[Future, A, List[B]]
    .run(input)         
2 голосов
/ 21 июня 2019
def runSequentially[A, B](lazyFutures: Seq[A => Future[B]])(input: A)(implicit ctx: ExecutionContext): Future[List[B]] =
  lazyFutures.foldLeft(Future.successful(List.empty[B])) { (futAcc, f) =>
    futAcc.flatMap { acc =>
      f(input).flatMap { result =>
        result :: acc
      }
    }
  }.map(_.reverse)

Должен сделать трюк (еще не проверял).При добавлении к списку и обращении сложность составляет O (n), а добавление - O (n ^ 2), поскольку добавление - O (n), а добавление выполняется n раз.

0 голосов
/ 21 июня 2019

Это то, что я придумал, которое работает

def runSequentially[A, B](lazyFutures: List[A ⇒ Future[B]])(input: A): Future[List[B]] = {
      lazyFutures.foldLeft(Future.successful(List.empty[B])) { (acc, curr) ⇒
        for {
          a ← acc
          c ← curr(input)
        } yield c :: a
      }
    }

...