คุณสามารถทำได้ด้วยฟิวเจอร์สเพียงอย่างเดียว นี่คือการนำไปใช้งานอย่างหนึ่ง โปรดทราบว่าจะไม่ยุติการดำเนินการก่อนกำหนด! ในกรณีนี้คุณต้องทำสิ่งที่ซับซ้อนมากขึ้น (และอาจใช้การหยุดชะงักด้วยตัวคุณเอง) แต่ถ้าคุณไม่ต้องการรอสิ่งที่จะไม่ทำงานต่อไปสิ่งสำคัญคือรอให้สิ่งแรกเสร็จสิ้นและหยุดเมื่อไม่มีสิ่งใดเหลืออยู่หรือคุณมีข้อยกเว้น:
import scala.annotation.tailrec
import scala.util.{Try, Success, Failure}
import scala.concurrent._
import scala.concurrent.duration.Duration
import ExecutionContext.Implicits.global
@tailrec def awaitSuccess[A](fs: Seq[Future[A]], done: Seq[A] = Seq()):
Either[Throwable, Seq[A]] = {
val first = Future.firstCompletedOf(fs)
Await.ready(first, Duration.Inf).value match {
case None => awaitSuccess(fs, done)
case Some(Failure(e)) => Left(e)
case Some(Success(_)) =>
val (complete, running) = fs.partition(_.isCompleted)
val answers = complete.flatMap(_.value)
answers.find(_.isFailure) match {
case Some(Failure(e)) => Left(e)
case _ =>
if (running.length > 0) awaitSuccess(running, answers.map(_.get) ++: done)
else Right( answers.map(_.get) ++: done )
}
}
}
นี่คือตัวอย่างของการดำเนินการเมื่อทุกอย่างทำงานได้ดี:
scala> awaitSuccess(Seq(Future{ println("Hi!") },
Future{ Thread.sleep(1000); println("Fancy meeting you here!") },
Future{ Thread.sleep(2000); println("Bye!") }
))
Hi!
Fancy meeting you here!
Bye!
res1: Either[Throwable,Seq[Unit]] = Right(List((), (), ()))
แต่เมื่อมีสิ่งผิดปกติเกิดขึ้น:
scala> awaitSuccess(Seq(Future{ println("Hi!") },
Future{ Thread.sleep(1000); throw new Exception("boo"); () },
Future{ Thread.sleep(2000); println("Bye!") }
))
Hi!
res2: Either[Throwable,Seq[Unit]] = Left(java.lang.Exception: boo)
scala> Bye!