执行N次Scala Future

时间:2019-03-17 16:01:31

标签: scala http asynchronous

我试图找到一种更优雅的方法来执行两次函数,该函数返回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 个答案:

答案 0 :(得分:2)

If you need to make two sequential calls to a method that returns Future, you can use flatMap.

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

This will not start the second post operation until the first one completes.

If you have multiple chained calls you can use foldLeft on a Range to apply this the appropriate number of times:

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

In practice you would probably use the value from the Range to track progress on this operation rather than discarding it.

答案 1 :(得分:1)

理想情况下,您需要这样的东西:

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

但是,如果您真的希望它是连续的,则此操作不起作用,因为Future.sequence急切地评估Stream并并行开始所有期货。对于该问题here,有一些解决方案。例如,here's用户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)))

答案 2 :(得分:0)

这应该是全部:

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