Ответ 1
"Обещание и будущее" - это взаимодополняющие концепции. Будущее - это ценность, которая будет получена, ну, когда-нибудь в будущем, и вы сможете делать что-то с ней, когда это событие произойдет. Это, следовательно, конечная точка чтения или вывода вычислений - это то, что вы извлекаете из значения.
Обещание, по аналогии, является письменной стороной вычисления. Вы создаете обещание, которое является местом, где вы поместите результат вычисления, и с этого обещания вы получите будущее, которое будет использоваться для чтения результата, который был внесен в обещание. Когда вы выполните обещание, либо сбой или успех, вы будете запускать все поведение, которое было привязано к связанному Будущему.
Что касается вашего первого вопроса, как это может быть для обещания p, мы имеем p.future == p
. Вы можете представить это как буфер с одним элементом - контейнер, который изначально пуст, и вы можете послесловия сохранить одно значение, которое станет его содержимым навсегда. Теперь, в зависимости от вашей точки зрения, это одновременно и обещание, и будущее. Это обещание для кого-то, кто намеревается записать значение в буфере. Это будущее для тех, кто ждет, чтобы это значение было помещено в буфер.
В частности, для Scala параллельного API, если вы посмотрите на черту Promise в здесь, вы можете увидеть, как методы из объекта-спутника Promise реализовано:
object Promise {
/** Creates a promise object which can be completed with a value.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
/** Creates an already completed Promise with the specified exception.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
/** Creates an already completed Promise with the specified result.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
}
Теперь эту реализацию promises, 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
}
}
Итак, как вы можете видеть, результат, который вы получаете от своего блока производителя, выливается в обещание.
LATER EDIT:
Что касается использования в реальном мире: большую часть времени вы не будете иметь дело с promises напрямую. Если вы будете использовать библиотеку, которая выполняет асинхронное вычисление, то вы просто будете работать с фьючерсами, возвращаемыми библиотечными методами. promises в этом случае создаются библиотекой - вы просто работаете с чтением в конце того, что делают эти методы.
Но если вам нужно реализовать собственный асинхронный API, вам придется приступить к работе с ними. Предположим, вам нужно реализовать асинхронный HTTP-клиент поверх, скажем, Netty. Тогда ваш код будет выглядеть примерно так:
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}