同步2个或更多Futures的计算

时间:2014-01-03 14:12:53

标签: scala parallel-processing future

我发现我无法弄清楚如何同步2个或更多Futures的计算:

val fs = List(1, 2, 3) map { x => Future { /* some computation depending on x... */ } }
fs(0) onComplete {
  case Success(x) => 
    fs(1) onComplete { 
      case Success(x) => 
        fs(2) onComplete ....
}

这看起来不合理。

我想从fs获取所有值。我该怎么做?

4 个答案:

答案 0 :(得分:9)

使用Future.traverse

val inList = List(1, 2, 3)
val fs = Future.traverse(inList) { x =>
  Future {
    /* some computation depending on x... */
  }
}

fs onSuccess { case outList => 
  ...
}

如果任何元素失败,这将失败。

如果您想要所有结果,无论失败或成功,那么最好的方法是recover他们,将结果包装在Try的实例中:

def asyncFunc(i: Int): Future[String] = ...

val inList = List(1, 2, 3)
val rawResults = inList.map(asyncFunc)
val recoveredResults = rawResults.map(Success(_)).recover(case x => Failure(x))

val completedResults = Future.sequence(recoveredResults)

completedResults onSuccess { case outList =>
  outList map {
    case Success(s) => ...
    case Failure(t) => ...
  }
}

提示:如果你做了很多这样的事情,通常更容易确保所有你的异步方法成功完成Future[Try[T]]的实例,而不是Future

中嵌入的任何错误

这样的事情:

def slowFunc(i: Int): String = ...
def asyncFunc(i: Int): Future[Try[String]] = Future { Try { slowFunc(i) } }

val inList = List(1, 2, 3)
val results = Future.traverse(inList)(asyncFunc)

results onSuccess { case outList =>
  outList map {
    case Success(s) => ...
    case Failure(t) => ...
  }
}

答案 1 :(得分:4)

您可以使用Future.sequenceList[Future]转换为Future[List]

val fs = List(1, 2, 3) map { x => Future(x * x) }
val f = Future.sequence(fs)
f.onComplete(println(_))

将打印Success(List(1, 4, 9))

答案 2 :(得分:1)

在Future配对对象中有一个帮助方法:

val fs: List[Future[Int]] = List(1, 2, 3) map { x => Future { /* some computation depending on x... */ } }
val allFs: Future[List[Int]] = Future.sequence(fs)

答案 3 :(得分:0)

您也可以使用for语句。

val f1 : Future[A] = Future { /* whatever */ }
val f2 : Future[B] = Future { /* whatever */ }
val results : Future[(A,B)] = for {
   f1Result <- f1
   f2Result <- f2
} yield(f1Result, f2Result)

重要的是在for语句之前启动期货(f1和f2),否则第二个期货将等到第一个结束。