Я читаю SIP-14, и концепция Future
имеет смысл и проста для понимания. Но есть два вопроса Promise
:
SIP говорит
Depending on the implementation, it may be the case that p.future == p
. Как это может быть? Есть два разных типа,Future
аPromise
не два?Когда мы должны использовать
Promise
? Примерproducer and consumer
кода:import scala.concurrent.{ future, promise } val p = promise[T] val f = p.future val producer = future { val r = produceSomething() p success r continueDoingSomethingUnrelated() } val consumer = future { startDoingSomething() f onSuccess { case r => doSomethingWithResult() } }
легко читать, но действительно ли нам нужно так писать? Я пытался реализовать это только с Future и без Promise вот так:
val f = future {
produceSomething()
}
val producer = future {
continueDoingSomethingUnrelated()
}
startDoingSomething()
val consumer = future {
f onSuccess {
case r => doSomethingWithResult()
}
}
В чем разница между этим и данным примером и для чего требуется Promise?
scala
concurrency
xiefei
источник
источник
Future
иPromise
это два разных типа, но, как вы можете видеть из github.com/scala/scala/blob/master/src/library/scala/concurrent/ ... эта конкретнаяPromise
реализация также расширяетсяFuture
.Ответы:
Обещание и будущее - это взаимодополняющие концепции. Будущее - это значение, которое будет извлечено когда-нибудь в будущем, и вы можете что-нибудь делать с ним, когда это событие произойдет. Следовательно, это конечная точка чтения или вывода вычисления - это то, из чего вы получаете значение.
По аналогии, обещание - это записывающая сторона вычислений. Вы создаете обещание, которое является местом, куда вы помещаете результат вычисления, и из этого обещания вы получаете будущее, которое будет использоваться для чтения результата, помещенного в обещание. Когда вы выполните обещание, либо неудачно, либо успешно, вы активируете все поведение, которое было привязано к соответствующему будущему.
Что касается вашего первого вопроса, как может быть, что для обещания p у нас есть
p.future == p
. Вы можете представить это как буфер с одним элементом - контейнер, который изначально пуст, а после него вы можете сохранить одно значение, которое навсегда станет его содержимым. Теперь, в зависимости от вашей точки зрения, это и обещание, и будущее. Это обещание для тех, кто намеревается записать значение в буфер. Это будущее для тех, кто ждет, пока это значение будет помещено в буфер.В частности, для параллельного API Scala, если вы посмотрите на черте 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)) }
Теперь эти реализации обещаний, 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 }
источник
Promise
s должен быть в коде реализации.Future
- это приятная вещь, доступная только для чтения, которую вы можете предоставить клиентскому коду. Кроме того,Future.future{...}
иногда синтаксис может быть громоздким.def makeHTTPCall(request: Request): Future[Response] = { Future { registerOnCompleteCallback(buffer => { val response = makeResponse(buffer) response }) } }
registerOnCompleteCallback()
завершения. Кроме того, он не возвращаетсяFuture[Response]
.Future[registerOnCompleteCallback() return type]
Вместо этого он возвращается .