ImはFuture.traverseを使用して、実行の順序が保証されています。私の関数fn
は呼び出されなければならず、未来は次の要素に対して実行される前に完了しなければなりません。Future.traverseは実行順序を保証しますか
val xs = Seq[T] ???
def fn(t: T): Future[Unit] = ???
Future.traverse(xs)(fn)
おかげで、
ImはFuture.traverseを使用して、実行の順序が保証されています。私の関数fn
は呼び出されなければならず、未来は次の要素に対して実行される前に完了しなければなりません。Future.traverseは実行順序を保証しますか
val xs = Seq[T] ???
def fn(t: T): Future[Unit] = ???
Future.traverse(xs)(fn)
おかげで、
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())
が私にそれのように
を見ていない非同期および非blockinglyフューチャー[TraversableOnce [BにTraversableOnce [A]を変換]]を使用して、A => Future [B]を呼び出します。これは、パラレルマップを実行する場合に便利です。
具体的にはドキュメントには記載されていませんので、より効果的な方法が存在する場合は契約が変更される可能性があります。また、「並列マップ」についても言及しています。これは、実行順序を保持する可能性が低いという別のヒントです。
は、すでに述べた:いいえ、traverse
はしていません(必ずしも[1])変換を適用要素を順番に、完了するまで繰り返す。
ただし、このようなlinearize
おそらく、何かに同等のものを作ることができます:
import scala.concurrent._
import scala.collection.mutable.Builder
import scala.collection.generic.CanBuildFrom
import language.higherKinds
/**
* Linearize asynchronously applies a given function in-order to a sequence of values, producing a Future with the result of the function applications.
* Execution of subsequent entries will be aborted if an exception is thrown in the application of the function.
*/
def linearize[T, U, C[T] <: Traversable[T]](s: C[T])(f: T => Future[U])(implicit cbf: CanBuildFrom[C[T], U, C[U]], e: ExecutionContext): Future[C[U]] = {
def next(i: Iterator[T], b: Builder[U, C[U]]): Future[C[U]] =
if(!i.hasNext) Future.successful(b.result)
else Future.unit.flatMap(_ => f(i.next()).flatMap(v => next(i, b += v)))
next(s.toIterator, cbf(s))
}
1:あなたはシーケンシャル効果カントーを達成同期ECを想像できます。
私がソースに達することができなかった理由は、署名/ドキュメントが変更されずに実装が変更される可能性があるということでした。 ソースそのものが順序付けされていないと言っている場合は間違いですが、偽陽性と偽陰性です。 –
私にとっては、この動作についてのドキュメントが必要です。メソッドの記述から使用法の例は直接後にはありません。 – Zernike