如何在Scala中解决一组Future

22

我有一个返回Future的调用。然而,我需要进行n次调用,这样我就会得到n个Futures。 我想知道在继续之前如何让所有Futures都得到解决(而不阻塞服务器)

例如,

while(counter < numCalls){
    val future = call(counter)
    future.map{  x =>
        //do stuff
    }
    counter += 1 
}

//Now I want to execute code here after ALL the futures are resolved without 
//blocking the server

你可以将yield与futures一起使用。 - Stefan Kunze
3个回答

54
你可以使用 Future.sequence(futureList)List[Future[X]] 转换为 Future[List[X]]。而由于后者只是一个简单的 Future,你可以借助 Await.ready 或类似的帮助器等待它完成。

因此,你需要保留生成的 future 列表。例如:

val futures = new ListBuffer[Future[X]]
while(counter < numCalls) {
    val future = call(counter)
    futures += future
    future.map { x =>
        //do stuff
    }
    counter += 1 
}
val f = Future.sequence(futures.toList)
Await.ready(f, Duration.Inf)

你也可以这样写:

val futures = (1 to numCalls).map(counter => {
    f = call(counter)
    f.map(x => ...)
    f
})
Await.ready(Future.sequence(futures), Duration.Inf)

8
除非你调用 Await.ready 方法,否则你不会被阻塞。这在举例说明时还好,但在生产代码中应避免阻塞,除非你确实无法避免……而你几乎总是可以避免阻塞。 - Christopher Hunt
抱歉,我匆忙之中复制了错误的代码行。我本意是:val f = Future.sequence(futures.toList)。最终我使用了f.map来等待它的解决。 - user2816456

6
更加实用一点:
val futures = for {
  c <- 0 until 10
   } yield {
    val f = call(c) 
    f onSuccess {
      case x =>
      // Do your future stuff with x
    }
    f
  }
Future.sequence(futures)

这个答案相比被接受的答案更加实用吗? - uncaught_exceptions

6
我理解您想在 Futures 完成后执行某些操作,例如回调,而不会阻塞原始调用。那么您应该像这样做:
val futures = for (...) yield {
  future {
  ...
  }
}

val f = Future sequence futures.toList

f onComplete {
  case Success(results) => for (result <- results) doSomething(result)
  case Failure(t) => println("An error has occured: " + t.getMessage)
}

http://docs.scala-lang.org/overviews/core/futures.html

这里讨论的是在不使用 await 时如何等待多个 Futures 完成并对所有结果进行操作。关键是使用 Future.sequence 将多个 futures 组合在一起,然后使用回调函数处理聚合结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接