#scala #future
#scala #будущее
Вопрос:
Я учусь Future
на Scala, и у меня есть следующий фрагмент кода. Я генерирую случайные метки на основе первой буквы в названии. Для следующего сценария я ожидаю, что список будет напечатан этим onComplete
методом. Но он ничего не печатает.
def randomMark(name:String) = name(0) match {
case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
case _ => Thread.sleep(500); 80
}
import scala.concurrent._
import concurrent.ExecutionContext.Implicits.global
val returns = Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) )
Thread.sleep(550)
returns onComplete { e => { val y1 = e.getOrElse("Error"); println(y1) } }
//This println statement does not execute. I expect a list List(99,99,80) to be printed
Может кто-нибудь, пожалуйста, помочь мне понять, почему функциональный литерал, который я предоставляю для onComplete
метода, не выполняется?
Спасибо!
Комментарии:
1. Если это целая программа, то она просто завершается, не дожидаясь завершения future. Попробуйте добавить
Await.ready(returns, Duration.Inf)
Ответ №1:
Скорее всего, потому, что вам нужно дождаться результата, потому onComplete
что это асинхронная операция.
import scala.concurrent.duration._
import scala.concurrent._
def randomMark(name:String) = name(0) match {
case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
case _ => Thread.sleep(500); 80
}
import scala.concurrent._
import concurrent.ExecutionContext.Implicits.global
val returns = Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) )
Thread.sleep(550)
returns onComplete { e => { val y1 = e.getOrElse("Error"); println(y1) } }
println("Waiting futures to be completed")
Await.ready(returns, 5.seconds)
println("Futures to be completed")
Распечатка закончилась:
Waiting futures to be completed
List(99, 99, 80)
Futures to be completed
Scatie: https://scastie.scala-lang.org/SWv18p8RTtuo7nMNHNHMoQ
Комментарии:
1. Спасибо, Иван! Когда я поменял местами последние два оператора в своей программе, я получил ожидаемый результат. Спасибо, что уделили мне время.
Ответ №2:
Поскольку обратные вызовы выполняются асинхронно, вам нужно будет дождаться завершения обратного вызова перед завершением работы программы. В этом случае, если вы хотите дождаться завершения обратного вызова, вам нужно каким-то образом сигнализировать о его завершении. В следующем примере я использую обещание:
def randomMark(name:String) = name(0) match {
case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
case _ => Thread.sleep(500); 80
}
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
val returns = Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) )
val returns: scala.concurrent.Future[List[Int]] = Future(<not completed>)
val p = Promise[Unit]()
returns onComplete { e => { val y1 = e.getOrElse("Error"); println(y1); p.success(()) } }
Await.ready(p.future, 5.seconds)
Но вы могли бы вместо этого использовать andThen
следующее:
def randomMark(name:String) = name(0) match {
case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
case _ => Thread.sleep(500); 80
}
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
val returns =
Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) ) andThen
{ case e => { val y1 = e.getOrElse("Error"); println(y1) } }
Await.ready(returns, 5.seconds)
Комментарии:
1. Спасибо за подробное объяснение, Виктор! Я не понял, что позиции последних двух операторов в моем примере. Когда я поменял их местами, я получил результат.