Future.sequenceは1つずつ順番に実行される訳じゃない
sequenceっていう名前からどうしても順序を意識してしまって順番に(直列に)実行されるものだと思っていた。 でもそうじゃなかった。
Future.applyの場合
ためしに、こんな処理を書いてみる。1から10までを1s待って出力するだけのやつ。
def process: Future[Seq[Int]] = Future.sequence { for { i <- 1 to 10 } yield { Future { println(s"start -> ${i.toString} ${System.currentTimeMillis}") Thread.sleep(1000) println(s"end -> ${i.toString} ${System.currentTimeMillis}") i } } }
これを実行すると、出力はこうなる。同時に4つの処理が走るみたいだ。並列で同時に実行されているので全ての処理が終わるまでに3秒ぐらいで終わっている。ただ、最終的な結果は、Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
となって順番通りになっている。
scala> Await.result(process, Duration.Inf) start -> 1 1459695509918 start -> 3 1459695509919 start -> 2 1459695509919 start -> 4 1459695509919 end -> 3 1459695510923 end -> 4 1459695510923 end -> 1 1459695510923 start -> 6 1459695510923 start -> 7 1459695510923 end -> 2 1459695510923 start -> 5 1459695510923 start -> 8 1459695510923 end -> 8 1459695511929 end -> 7 1459695511929 start -> 9 1459695511929 start -> 10 1459695511929 end -> 5 1459695511929 end -> 6 1459695511929 end -> 9 1459695512933 end -> 10 1459695512933 res24: Seq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Future.successfulの場合
こんな風にFuture.successfulで書き直して
def process: Future[Seq[Int]] = Future.sequence { for { i <- 1 to 10 } yield { Future.successful { println(s"start -> ${i.toString} ${System.currentTimeMillis}") Thread.sleep(1000) println(s"end -> ${i.toString} ${System.currentTimeMillis}") i } } }
実行すると、順番に実行される。実行時間も10秒ぐらいかかってる。結果もVector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
で同じになってる。
scala> Await.result(process, Duration.Inf) start -> 1 1459696443179 end -> 1 1459696444180 start -> 2 1459696444180 end -> 2 1459696445180 start -> 3 1459696445180 end -> 3 1459696446180 start -> 4 1459696446181 end -> 4 1459696447181 start -> 5 1459696447182 end -> 5 1459696448186 start -> 6 1459696448186 end -> 6 1459696449187 start -> 7 1459696449187 end -> 7 1459696450188 start -> 8 1459696450188 end -> 8 1459696451188 start -> 9 1459696451188 end -> 9 1459696452188 start -> 10 1459696452188 end -> 10 1459696453191 res25: Seq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Future.successful
で同じことをした場合は、順番に行われる。これは、Future.apply
とFuture.successful
の処理をとるときに、名前渡しかそうじゃないかが関係ある。(となんとなく思う)
scala/Future.scala at 2.11.x · scala/scala · GitHub
def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = impl.Future(body) def successful[T](result: T): Future[T] = Promise.successful(result).future