如何在scala中使用Futures并行执行函数调用

时间:2017-04-23 07:31:51

标签: multithreading scala apache-spark parallel-processing future

我想用不同的参数调用func(),并且应该并行调用此函数。

for(i <- 0 to count) {
    Future {
        for(j <- 0 to n_count) {
            Future {
                func(a,b, c(i), d(j))
            }
        }
    }
}

这是正确的方法吗?

我的功能也没有返回任何东西。那么如何知道执行是并行运行还是创建了多少线程。请在Scala中提供此类方案的完整代码。

2 个答案:

答案 0 :(得分:1)

这非常简单,因为这个原因,scala会为您提供Future.sequenceFuture.traverse

通过将M[Future[T]]类型的任何集合转换为Future[M[T]]的集合,它们大致以相同的方式工作,但它们的使用方式不同。

val actions = List(Future(5), Future(6), Future(7))
val executed = Future.sequence(actions) map (l => println(l.mkString()) // 5, 6 ,7

现在Future.traverse在语义上是不同的,因为您为它提供了一个M[A]或一组元素,然后是一个将这些元素转换为未来的函数。例如:

val userIds = List(1, 2, 3, 4 , 5)
// let's pretend this calls an SQL DB
def userById(id: Int): Future[Option[User]]
Future.traverse(userIds)(id => userById(id))

就执行语义而言,两个构造都并行执行所有期货,如果任何期货失败则失败。没有保证期货按顺序执行。

关闭主题,但幸运的是,一次编写一个&#34;一次逻辑非常容易 你自己。这是通过从元素&#34;内部&#34;移动产生Future的函数来实现的。 for block。 Scala中的期货总是在已经开始的状态下创建,这使得它们更难以推理。

def sequencedTraverse[
    A,
    B,
    M[X] <: TraversableOnce[X]
  ](in: M[A])(fn: A => Future[B])(implicit
    executor: ExecutionContextExecutor,
    cbf: CanBuildFrom[M[A], B, M[B]]
  ): Future[M[B]] = {
    in.foldLeft(Future.successful(cbf(in))) { (fr, a) =>
      for (r <- fr; b <- fn(a)) yield r += b
    }.map(_.result())
  }

答案 1 :(得分:0)

基于@flavian的优秀答案:

scala> val a = "a"
a: String = a

scala> val b = "b"
b: String = b

scala> val c = List("x","y","z")
c: List[String] = List(x, y, z)

scala> val d = List("u","v","w")
d: List[String] = List(u, v, w)

scala> def func(a: String, b: String, c: String, d: String) = a + b + c + d
func: (a: String, b: String, c: String, d: String)String

scala> val futures = for{i <- c; j <- d} yield Future(func(a,b,i,j))
futures: List[scala.concurrent.Future[String]] = List(Future(Success(abxu)), Future(Success(abxv)), Future(Success(abxw)), Future(Success(abyu)), Future(Success(abyv)), Future(Success(abyw)), Future(Success(abzu)), Future(Success(abzv)), Future(Success(abzw)))

scala> Future.sequence(futures)
res0: scala.concurrent.Future[List[String]] = Future(<not completed>)

scala> res0
res1: scala.concurrent.Future[List[String]] = Future(Success(List(abxu, abxv, abxw, abyu, abyv, abyw, abzu, abzv, abzw)))