Vaat ve Gelecek birbirini tamamlayan kavramlardır. Gelecek, gelecekte bir ara geri getirilecek bir değerdir ve bu olay gerçekleştiğinde onunla bir şeyler yapabilirsiniz. Bu nedenle, bir hesaplamanın okuma veya çıkış uç noktasıdır - bu, bir değeri elde ettiğiniz bir şeydir.
Bir Söz, benzetme yoluyla, hesaplamanın yazım tarafıdır. Hesaplamanın sonucunu koyacağınız yer olan bir söz yaratırsınız ve bu sözden, sözde verilen sonucu okumak için kullanılacak bir gelecek elde edersiniz. Başarısızlık veya başarı ile bir Sözü tamamladığınızda, ilişkili Geleceğe bağlı olan tüm davranışları tetikleyeceksiniz.
İlk sorunuzla ilgili olarak, sahip olduğumuz bir söz için bu nasıl olabilir p.future == p
? Bunu tek öğeli bir arabellek gibi hayal edebilirsiniz - başlangıçta boş olan bir kap ve sonradan, içeriği sonsuza kadar olacak bir değeri depolayabilirsiniz. Şimdi, bakış açınıza göre bu hem bir Vaat hem de bir Gelecek. Tampondaki değeri yazmak isteyen biri için söz veriliyor. Bu değerin tampona konulmasını bekleyen biri için gelecek.
Spesifik olarak, Scala eşzamanlı API'si için, burada Promise özelliğine bir göz atarsanız, Promise tamamlayıcı nesnesindeki yöntemlerin nasıl uygulandığını görebilirsiniz:
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))
}
Şimdi, bu vaatlerin uygulanması, DefaultPromise ve KeptPromise burada bulunabilir . Her ikisi de aynı adı taşıyan temel küçük bir özelliği genişletir, ancak farklı bir pakette bulunur:
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
Böylece ne demek istediklerini anlayabilirsiniz p.future == p
.
DefaultPromise
yukarıda bahsettiğim KeptPromise
tampon, yaratılışından gelen değerle bir tampon.
Örneğinizle ilgili olarak, orada kullanacağınız gelecekteki blok aslında perde arkasında bir vaat yaratıyor. Buradafuture
in tanımına bakalım :
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
Yöntemler zincirini takip ederek, impl . Gelecek :
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
}
}
Gördüğünüz gibi, yapımcı bloğunuzdan aldığınız sonuç bir söze dönüşüyor.
DAHA SONRA DÜZENLEME :
Gerçek dünya kullanımıyla ilgili olarak: Çoğu zaman sözlerle doğrudan ilgilenmezsiniz. Eşzamansız hesaplama yapan bir kitaplık kullanacaksanız, o zaman kitaplığın yöntemleri tarafından döndürülen geleceklerle çalışacaksınız. Sözler, bu durumda, kütüphane tarafından yaratılır - sadece bu yöntemlerin ne yaptığını okuyarak çalışıyorsunuz.
Ancak kendi eşzamansız API'nizi uygulamanız gerekiyorsa, onlarla çalışmaya başlamanız gerekir. Diyelim ki Netty'nin üzerine bir zaman uyumsuz HTTP istemcisi uygulamanız gerektiğini varsayalım. O zaman kodunuz bir şekilde şöyle görünecek
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}