简体   繁体   中英

How to execute list of scala futures sequentially

I want to execute List of functions which returns futures sequentially.

What could be the possible implementations for following method:

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

Test

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)

  }

This should print:

1
2
3

Try creating a pool with one thread and use Future.traverse like so

implicit val singleThreadEc: ExecutionContext = 
  ExecutionContext.fromExecutor(Executors.newSingleThreadExecutor())

def runSequentially[A, B](lazyFutures: List[A ⇒ Future[B]])(input: A): Future[List[B]] =
  Future.traverse(lazyFutures)(f => f(input))
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)

Should do the trick (haven't tested it). By prepending to the list and reversing, the complexity is O(n), while appending is O(n^2), since appending is O(n) and the append is done n times.

You can also use cats and 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)         

This is what I came up with which does work

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
      }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM