Futures and Promises / Фьючи и Промисы: Futures
| Английский оригинал | Перевод на русский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
Фьюча - это объект хранящий значение, которое может быть доступным в какой-то момент времени. Обычно, это значение является результатом какого-то вычисления: 2heoh 11.11.13 в 06:35 |
|
|
Если вычисление еще не завершено, мы говорим что фьюча не завершена(разрешена). 2heoh 11.11.13 в 06:36 |
||
|
Если вычисление завершено со значением или с исключением, то мы говорим что фьюча завершена(разрешена). 2heoh 11.11.13 в 06:37 |
||
|
Завершение может принимать одну из двух видов: 2heoh 11.11.13 в 06:38 |
||
|
Когда фьюча заврешена со значением, мы говорим что она была завершена(разрешена) успешно с этим значением. 2heoh 11.11.13 в 06:40 |
||
|
Когда фьюча завершена с вызванным исключением в результате вычисления, мы говорим, что фьюча завершилась ошибкой (пофейлилась) с этим исключением. 2heoh 11.11.13 в 06:42 |
||
|
Фьюча имеет важное свойство: она может быть присвоена (переменной) только один раз. В результате присвоения объекту фьючи значения или исключения, объект становится неизменяемым и не может быть переопределен. 2heoh 11.11.13 в 06:45 |
||
|
Самый простой способ создать объект фьючи - вызвать метод future, который начинает асинхронное вычисление и возвращает фьючу, хранящую результат этого вычисления. Значение становится доступны сразу после завершения фьючи. 2heoh 11.11.13 в 06:47 |
||
|
Обратите внимание, что Future[T] это тип который определяет объект фьючи в то время как future это метод, который создает и планирует асинхронное вычисление и затем возвращает объект фьючи, который будет выполнен со значением этого вычисления. 2heoh 11.11.13 в 06:51 |
||
|
Лучше всего это показать примером. 2heoh 11.11.13 в 06:52 |
||
|
Предположим, что мы хотим использовать гипотетическое API некой популярной социальной сети для получения списка друзей пользователя. Мы создаем новую сессию и посылаем запрос для получения списка друзей определенного пользователя: 2heoh 11.11.13 в 07:01 |
||
|
import scala.concurrent._ 2heoh 11.11.13 в 07:32 |
||
|
Выше, мы сначала импортируем содержимое пакета scala.concurrent для того чтобы нам доступен тип Future и конструктор фьюч. Второй impot мы объясним скоро. 2heoh 11.11.13 в 07:05 |
||
|
Затем мы инициализируем переменную сессии, которую мы будем использовать для отсылки запросов на сервер, используя гипотетический метод createSessionFor, который возвращает объект типа List[Friend]. Для получения списка друзей пользователя, запрос посылается по сети, а это может занимать продолжительное время. Это показано при помощи вызова метода getFriends. Для оптимального использования ЦПУ до тех пор пока ответ не будет получен, мы не должны блокировать остальную часть программы, это вычисление должно быть отложено асинхронно. И именно это и делает метод future - он выполняет указанное вычисление конкурентно, в данном случае, посылает запрос на сервер и ждет ответ. 2heoh 11.11.13 в 07:13 |
||
|
Список друзей становится доступным в фьюче f сразу как сервер ответит. 2heoh 11.11.13 в 07:14 |
||
|
Неуспешный попытка может привести к исключению. В следующем примере сессия некорректно инициализирована, и поэтому вычисление в блоке future вызовет NullPointerException. Здесь фьюча f завершится исключением, а не будет выполнена успешно: 2heoh 11.11.13 в 07:17 |
||
|
val session = null 2heoh 11.11.13 в 07:32 |
||
|
Строка import ExecutionContext.Implicits.global импортирует глобальный контекст выполнения по умолчанию. Контексты выполнения выполняет задачи, которые подчиняются им (относятся к ним), и вы можете думать об контекстах выполнения как пуле тредов. Они присущи для метода future потому что они управляют как и когда асинхронное вычисление будет выполнено. Вы можете определить свои собственные контексты выполнения и использовать их со фьючами, но пока достаточно знать что вы можете импортировать контекст вычисления по умолчанию как показано выше. 2heoh 11.11.13 в 07:24 |
||
|
Наш пример основан на API гипотетической социальной сети, где вычисление состоит из отслыки сетевого запроса и ожидания ответа. Честно было бы показать пример с асинхронными вычислениями, которое вы могли бы попробовать "из коробки". Предположим у вас есть текстовый файл и вы хотите найти ближайшее место, в котором находится определенное слово. Это вычисление может вызывать блокировки во время получения содержимого файла с диска, и поэтому имеет смысл выполнять его конкурентно с остальными вычислениями. 2heoh 11.11.13 в 07:31 |
||
|
val firstOccurrence: Future[Int] = future { 2heoh 11.11.13 в 07:32 |
