Обещание и будущее - это взаимодополняющие концепции. Будущее - это значение, которое будет извлечено когда-нибудь в будущем, и вы можете что-нибудь делать с ним, когда это событие произойдет. Следовательно, это конечная точка чтения или вывода вычисления - это то, из чего вы получаете значение.
По аналогии, обещание - это записывающая сторона вычислений. Вы создаете обещание, которое является местом, куда вы помещаете результат вычисления, и из этого обещания вы получаете будущее, которое будет использоваться для чтения результата, помещенного в обещание. Когда вы выполните обещание, либо неудачно, либо успешно, вы активируете все поведение, которое было привязано к соответствующему будущему.
Что касается вашего первого вопроса, как может быть, что для обещания p у нас есть p.future == p
. Вы можете представить это как буфер с одним элементом - контейнер, который изначально пуст, а после него вы можете сохранить одно значение, которое навсегда станет его содержимым. Теперь, в зависимости от вашей точки зрения, это и обещание, и будущее. Это обещание для тех, кто намеревается записать значение в буфер. Это будущее для тех, кто ждет, пока это значение будет помещено в буфер.
В частности, для параллельного API Scala, если вы посмотрите на черте Promise в здесь вы можете увидеть , как реализуются методы от объекта - компаньона Promise:
object Promise {
def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
}
Теперь эти реализации обещаний, DefaultPromise и KeptPromise можно найти здесь . Оба они расширяют базовую маленькую черту, которая имеет одно и то же имя, но находится в другом пакете:
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
Итак, вы можете понять, что они имеют в виду p.future == p
.
DefaultPromise
- это буфер, о котором я говорил выше, а KeptPromise
это буфер со значением, введенным с момента его создания.
Что касается вашего примера, будущий блок, который вы там используете, фактически создает обещание за кулисами. Давайте посмотрим на определение future
в здесь :
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
Следуя цепочке методов, вы попадаете в impl.Future :
private[concurrent] object Future {
class PromiseCompletingRunnable[T](body: => T) extends Runnable {
val promise = new Promise.DefaultPromise[T]()
override def run() = {
promise complete {
try Success(body) catch { case NonFatal(e) => Failure(e) }
}
}
}
def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
val runnable = new PromiseCompletingRunnable(body)
executor.execute(runnable)
runnable.promise.future
}
}
Итак, как видите, результат, который вы получаете от вашего блока производителя, переливается в обещание.
ПОЗЖЕ РЕДАКТИРОВАТЬ :
Что касается реального использования: в большинстве случаев вы не будете иметь дело с обещаниями напрямую. Если вы будете использовать библиотеку, которая выполняет асинхронные вычисления, тогда вы просто будете работать с фьючерсами, возвращаемыми методами библиотеки. Обещания в этом случае создаются библиотекой - вы просто работаете с концом чтения того, что делают эти методы.
Но если вам нужно реализовать собственный асинхронный API, вам придется начать с ними работать. Предположим, вам нужно реализовать асинхронный HTTP-клиент поверх, скажем, Netty. Тогда ваш код будет выглядеть примерно так
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}