#scala #future
#scala #будущее
Вопрос:
Я не понимаю, как Future
работает Scala. Может кто-нибудь объяснить, что не так с кодом:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
val numbers = List(1,2,3,4,5,6,7,8,9,10)
def showNumbers() = {
numbers
}
val futueNumber = future {
showNumbers.filter((a: Int) => a % 2 == 0)
}
futueNumber onSuccess {
case resultList => resultList
}
futueNumber
Я ожидаю получить результат:
List(1,2,3,4,5,6,7,8,9,10)
Но REPL выводит:
res1: scala.concurrent.Future[List[Int]] = scala.concurrent.impl.Promise$DefaultPromise@3644febc
Пожалуйста, дайте мне короткую подсказку, как это исправить
Ответ №1:
Простой ответ заключается в том, что вам нужно дождаться будущего, чтобы ваш пример работал:
val result = Await.result(futureNumber, 1.second)
Однако цель future не в том, чтобы блокировать асинхронную работу, как Await
это происходит, а вместо этого использовать результат future, когда он становится доступным.
Ключом к использованию future
является понимание того, что на самом деле он не содержит значения ваших вычислений, а скорее обещает, что в какой-то момент в будущем он предоставит это значение.
Обычный вариант использования — это запрос, поступающий на сервер, который требует некоторой работы, которая может занять некоторое время и сама ждать ввода-вывода, например:
def receiveMsg(msg: String, caller: Caller) = {
doSomeAsyncWork(msg).map(response => caller.send(response)
}
Т.е. вы вызываетесь с объектом, у которого есть send
метод, который вы хотите вызвать по завершении doSomeAsyncWork
, но вы не хотите блокировать текущий поток до его future
завершения. Вместо этого вы map
future
, что означает, что response => caller.send(response)
будет вызван для вас, когда doSomeAsyncWork
будет сделано.
Ответ №2:
futureNumber имеет тип Future[List[Int]]
, поскольку вы определили его как таковой в
val futureNumber = future {
showNumbers.filter((a: Int) => a % 2 == 0)
}
Поэтому, когда вы печатаете futureNumber, это то, что печатается. Переменной не присваивается значение future! Если вы хотите напечатать значение будущего, вам нужно сделать это внутри обратного вызова onSucess:
futureNumber onSuccess {
case resultList => println(resultList)
}
Кроме того, вы можете заблокировать ожидание будущего с помощью
import scala.concurrent.ExecutionContext.Implicits.global
import duration._
val theList = scala.concurrent.Await.result(futureNumber, 10 seconds)
println(theList)
Хотя это может не сработать, если сделано в REPL.
Весь смысл Future
типа в том, что он действует как маркер, который предупреждает вас о наличии параллелизма и должен помочь вам лучше с ним справиться.