Scala: будущее в действии

#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 типа в том, что он действует как маркер, который предупреждает вас о наличии параллелизма и должен помочь вам лучше с ним справиться.