我正在使用Future.traverse,可以保证执行顺序。我的函数fn必须被调用,并且将来才能运行,然后运行下一个元素。

val xs = Seq[T] ???
def fn(t: T): Future[Unit] = ???
Future.traverse(xs)(fn)

谢谢,

最佳答案

在scala 2.11中实现traverse:

  def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
    in.foldLeft(successful(cbf(in))) { (fr, a) =>
      val fb = fn(a)
      for (r <- fr; b <- fb) yield (r += b)
    }.map(_.result())
val fb = fn(a)创建Future[B],然后再与先前创建的将来for (r <- fr; b <- fb) yield (r += b)组成。所以答案是否定的。没有执行顺序保证。

在Scala 2.12中,实现已更改:
def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
    in.foldLeft(successful(cbf(in))) {
      (fr, a) => fr.zipWith(fn(a))(_ += _)
    }.map(_.result())(InternalCallbackExecutor)

但是还是在与以前的fr链接(zipWith的第一个参数是“按值调用”)之前创建了“下一个”将来。

如果需要顺序遍历,则只需对2.11实现进行一些更改:
def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
    in.foldLeft(successful(cbf(in))) { (fr, a) =>
      for (r <- fr; b <- fn(a)) yield (r += b)
    }.map(_.result())

10-07 12:25
查看更多