Выполняя N раз Scala Future - PullRequest
       1

Выполняя N раз Scala Future

1 голос
/ 17 марта 2019

Я пытаюсь найти более элегантный способ выполнить 2 раза функцию, которая возвращает Future [HttpReponse], а затем использовать ответ 2-го вызова.

for {
    // function post returns a Future[HttpResponse]
    response <- post(uri, payload) // 1st
    response <- post(uri, payload) // 2end
} yield {
    // do something with the 2end response
}

Это неработа:

for {
    2 times response <- post(uri, payload)
} yield {
    // response becomes of type Any instead of HttpResponse
}

Ответы [ 3 ]

2 голосов
/ 18 марта 2019

Если вам нужно сделать два последовательных вызова метода, который возвращает Future, вы можете использовать flatMap.

post(uri, payload).flatMap(_ => post(uri, payload))

Это не запустит вторую post операцию, пока не завершится первая.

Если у вас есть несколько связанных вызовов, вы можете использовать foldLeft на Range, чтобы применить это соответствующее количество раз:

(0 to N-1).foldLeft(post(uri, payload)){
  case (prev, _) => prev.flatMap(_ => post(uri, payload))
}

На практике вы, вероятно, будете использовать значение из Range, чтобы отслеживать ход выполнения этой операции, а не отбрасывать ее.

1 голос
/ 17 марта 2019

В идеале вы хотели бы что-то вроде этого:

Future.sequence(Stream.fill(n)(post(uri, payload)))

Однако, если вы действительно хотите, чтобы он был последовательным, это не сработает, поскольку Future.sequence с нетерпением оценивает Stream и запускает все фьючерсы параллельно. Есть несколько решений этой проблемы здесь . Например, вот user eagle yuan версия последовательности, которая работает последовательно:

def seq[A, M[X] <: TraversableOnce[X]](in: M[() => Future[A]])(implicit cbf: CanBuildFrom[M[()=>Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = {
    in.foldLeft(Future.successful(cbf(in))) {
       (fr, ffa) => for (r <- fr; a <- ffa()) yield (r += a)
    } map (_.result())
}

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

seq(Seq.fill(n)(() => post(uri, payload)))
0 голосов
/ 17 марта 2019

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

val result = Seq.fill(2)(post(uri, payload)).last

Я проверил это с помощью этого кода:

 val result = Seq.fill(2)(dummyFut()).last

  def dummyFut(): Future[Long] = Future.successful{
    Thread.sleep(1000L)
    println(System.currentTimeMillis())
    System.currentTimeMillis()
  }

  result.foreach(println)

Это печатает:

1552852972738
1552852973749
1552852973749
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...