我正在使用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())