【问题标题】:Executing N times a Scala Future执行 N 次 Scala Future
【发布时间】:2019-03-18 06:57:20
【问题描述】:

我试图找到一种更优雅的方法来执行 2 次返回 Future[HttpReponse] 的函数,然后使用 2-end 调用的响应。

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
}

【问题讨论】:

  • 这两个调用应该同时执行还是顺序执行?
  • 依次:-)
  • 更新了我的答案以按顺序工作。

标签: scala http asynchronous


【解决方案1】:

如果您需要对返回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 中的值来跟踪此操作的进度,而不是丢弃它。

【讨论】:

    【解决方案2】:

    这应该是全部:

    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
    

    【讨论】:

    • 谢谢。有趣的是,它对我有用
    • @Martin 这实际上并没有按顺序运行期货。它只是在示例中看起来像,因为 pme 使用 Future.successful,它在同一线程上运行提供的代码,而不是 Future.apply。将Future.successful { 替换为Future {,您会发现它打印的时间不正确。
    • @BrianMcCutchon 感谢您指出这一点 - 所以我很幸运;(.
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-16
      • 1970-01-01
      • 2011-02-20
      • 1970-01-01
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      • 2019-10-25
      相关资源
      最近更新 更多