Scala.concurrent.Promise'ın kullanım örnekleri nelerdir?


94

SIP-14 okuyorum ve kavramı çok Futuremantıklı ve anlaşılması kolay. Ancak şu konularda iki sorum var Promise:

  1. SIP diyor Depending on the implementation, it may be the case that p.future == p. Bu nasıl olabilir? Are Futureve Promiseiki farklı türde değil?

  2. Ne zaman a kullanmalıyız Promise? Örnek producer and consumerkod:

    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()
        }
    }
    

okuması kolay ama gerçekten böyle yazmamız gerekiyor mu? Bunu sadece Future ile ve Promise olmadan şu şekilde uygulamaya çalıştım:

val f = future {
   produceSomething()
}

val producer = future {
   continueDoingSomethingUnrelated()
}

startDoingSomething()

val consumer = future {
  f onSuccess {
    case r => doSomethingWithResult()
  }
}

Bu ve verilen örnek arasındaki fark nedir ve bir Sözü gerekli kılan nedir?


İlk örnekte, continueDoingSomethingUnrelated (), aynı iş parçacığındaki üretmekSomething () sonrasında değerlendirir.
senia

1
1. soruyu yanıtlamak gerekirse, evet Futureve Promiseiki ayrı türdür , ancak github.com/scala/scala/blob/master/src/library/scala/concurrent/… adresinden görebileceğiniz gibi, bu özel Promiseuygulama da genişler Future.
Dylan

Yanıtlar:


118

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 {

  /** 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))

}

Ş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.

DefaultPromiseyukarıda bahsettiğim KeptPromisetampon, 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
    }

3
@xiefei Promises için kullanım durumu uygulama kodunda olmalıdır. Futuremüşteri koduna gösterebileceğiniz hoş, salt okunur bir şeydir. Ayrıca Future.future{...}sözdizimi bazen kullanışsız olabilir.
Dylan

11
Bunu şu şekilde görebilirsiniz: sözsüz bir geleceğe sahip olamazsınız. İlk etapta tamamlanan bir söz yoksa gelecek bir değer döndüremez. Sözler isteğe bağlı değildir, geleceğin zorunlu yazı tarafıdır. Sadece vadeli işlemlerle çalışamazsınız çünkü onlara dönüş değerini sağlayacak kimse olmaz.
Marius Danila

4
Sanırım gerçek dünya kullanımları derken neyi kastettiğinizi anlıyorum: Size bir örnek vermek için cevabımı güncelledim.
Marius Danila

2
@Marius: Verilen gerçek dünya örneğini göz önünde bulundurursak, makeHTTPCall böyle uygulanırsa ne olur: def makeHTTPCall(request: Request): Future[Response] = { Future { registerOnCompleteCallback(buffer => { val response = makeResponse(buffer) response }) } }
puneetk

1
@puneetk o zaman bir geleceğe sahip olacaksınız ve registerOnCompleteCallback()bittikten hemen sonra tamamlanır. Ayrıca geri dönmez Future[Response]. Onun Future[registerOnCompleteCallback() return type]yerine geri döner .
Evgeny Veretennikov
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.