执行n次Scala未来



我正在尝试找到一种更优雅的方式来执行2倍返回未来[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
}

如果您需要对返回Future的方法进行两个顺序调用,则可以使用flatMap

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

这不会启动第二个post操作,直到第一个操作完成。

如果您有多个链式电话,则可以在Range上使用foldLeft来应用此适当次数:

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

实际上,您可能会使用Range的值来跟踪此操作的进度而不是丢弃。

这应该全部:

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

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

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

但是,如果您真的希望它是顺序的,则无效,因为Future.sequence急切地评估Stream并并行启动所有期货。这里有一些解决方案。例如,此处是用户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)))

最新更新