Scala.concurrent.Promise के उपयोग के मामले क्या हैं?


93

मैं एसआईपी -14 पढ़ रहा हूं और Futureसही अर्थों और समझने में आसान बनाता है। लेकिन इसके बारे में दो सवाल हैं Promise:

  1. एसआईपी कहता है Depending on the implementation, it may be the case that p.future == p। यह कैसे हो सकता है? हैं Futureऔर Promiseदो अलग-अलग प्रकार नहीं हैं?

  2. हमें कब उपयोग करना चाहिए 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()
        }
    }
    

पढ़ना आसान है लेकिन क्या हमें वास्तव में ऐसा लिखने की आवश्यकता है? मैंने इसे केवल फ्यूचर के साथ और इस तरह के प्रोमिस के बिना लागू करने की कोशिश की:

val f = future {
   produceSomething()
}

val producer = future {
   continueDoingSomethingUnrelated()
}

startDoingSomething()

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

इस और दिए गए उदाहरण के बीच क्या अंतर है और क्या एक वादा आवश्यक है?


पहले उदाहरण में ContinueDoingSomethingUnrelated () एक ही थ्रेड में ProdSomething () के बाद मूल्यांकन करता है।
सेनिया

1
प्रश्न # 1 का उत्तर देने के लिए, हाँ Futureऔर Promiseदो अलग-अलग प्रकार हैं, लेकिन जैसा कि आप github.com/scala/scala/blob/master/src/library/scala/concurrent/ पर देख सकते हैं। यह विशेष रूप से Promiseलागू Futureभी होता है।
डायलन

जवाबों:


118

वादा और भविष्य पूरक अवधारणाएँ हैं। फ्यूचर एक ऐसा मूल्य है जिसे भविष्य में कभी भी प्राप्त किया जा सकता है। इसलिए, यह एक संगणना के पढ़ने या बाहर समापन बिंदु है - यह कुछ ऐसा है जिसे आप से एक मान प्राप्त करते हैं।

एक वादा, सादृश्य द्वारा, अभिकलन के लेखन पक्ष है। आप एक वादा बनाते हैं जो वह जगह है जहां आप गणना का परिणाम डालेंगे और उस वादे से आपको एक भविष्य मिलेगा जिसका उपयोग उस परिणाम को पढ़ने के लिए किया जाएगा जिसे वादे में डाल दिया गया था। जब आप एक वादा पूरा करेंगे, तो असफलता या सफलता से, आप उन सभी व्यवहारों को ट्रिगर करेंगे जो संबद्ध भविष्य से जुड़े थे।

आपके पहले प्रश्न के बारे में, यह कैसे हो सकता है कि एक वादा पी के लिए हमारे पास है p.future == p। आप इसे एकल-आइटम बफर की तरह कल्पना कर सकते हैं - एक कंटेनर जो शुरू में खाली है और आप बाद में एक मूल्य को संग्रहीत कर सकते हैं जो हमेशा के लिए इसकी सामग्री बन जाएगा। अब, आपके दृष्टिकोण के आधार पर यह एक वादा और भविष्य दोनों है। यह किसी ऐसे व्यक्ति के लिए वादा है जो बफर में मूल्य लिखने का इरादा रखता है। यह उस व्यक्ति के लिए एक भविष्य है जो उस मूल्य का इंतजार करता है जिसे बफर में रखा जाए।

विशेष रूप से, स्काला समवर्ती एपीआई के लिए, यदि आप यहां प्रॉमिस विशेषता पर एक नज़र डालते हैं, तो आप देख सकते हैं कि प्रोमिस साथी ऑब्जेक्ट से कैसे तरीके लागू होते हैं:

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

इसलिए, जैसा कि आप देख सकते हैं, आप अपने निर्माता ब्लॉक से जो परिणाम प्राप्त करते हैं वह एक वादा में डाला जाता है।

लेदर संस्करण :

वास्तविक दुनिया के उपयोग के बारे में: अधिकांश समय आप सीधे वादों से नहीं निपटेंगे। यदि आप एक पुस्तकालय का उपयोग करेंगे जो अतुल्यकालिक गणना करता है तो आप बस पुस्तकालय के तरीकों द्वारा लौटे वायदा के साथ काम करेंगे। वादे, इस मामले में, पुस्तकालय द्वारा बनाए गए हैं - आप बस उन तरीकों के पढ़ने के अंत के साथ काम कर रहे हैं।

लेकिन अगर आपको अपने स्वयं के अतुल्यकालिक एपीआई को लागू करने की आवश्यकता है, तो आपको उनके साथ काम करना शुरू करना होगा। मान लीजिए कि आपको सबसे ऊपर एक async HTTP क्लाइंट को लागू करने की आवश्यकता है, जो कहता है, Netty। तब आपका कोड कुछ इस तरह दिखाई देगा

    def makeHTTPCall(request: Request): Future[Response] = {
        val p = Promise[Response]
        registerOnCompleteCallback(buffer => {
            val response = makeResponse(buffer)
            p success response
        })
        p.future
    }

3
@xiefei Promises के लिए उपयोग मामला कार्यान्वयन कोड में होना चाहिए। Futureएक अच्छी, पढ़ी-लिखी चीज है जिसे आप ग्राहक कोड के सामने ला सकते हैं। इसके अलावा, Future.future{...}वाक्यविन्यास कभी-कभी बोझिल हो सकता है।
डायलन

11
आप इसे इस तरह देख सकते हैं: आपके पास बिना वादे के भविष्य नहीं हो सकता। यदि कोई वादा पूरा नहीं होता है, तो भविष्य में एक मूल्य वापस नहीं किया जा सकता है। वादे वैकल्पिक नहीं हैं, वे भविष्य का अनिवार्य लेखन पक्ष हैं। आप केवल वायदा के साथ काम नहीं कर सकते क्योंकि उन्हें वापसी मूल्य प्रदान करने के लिए कोई भी नहीं होगा।
मारियस डैनिला

4
मुझे लगता है कि मैं देख रहा हूं कि वास्तविक दुनिया के उपयोग से आपका क्या मतलब है: मैंने आपको एक उदाहरण देने के लिए अपनी प्रतिक्रिया अपडेट की है।
मारियस डनिला

2
@ मार्स: दिए गए वास्तविक-विश्व उदाहरण को देखते हुए, अगर मेकएचटीटीपी कॉल को इस तरह से लागू किया जाए तो क्या होगा: def makeHTTPCall(request: Request): Future[Response] = { Future { registerOnCompleteCallback(buffer => { val response = makeResponse(buffer) response }) } }
पोनेटेक

1
@puneetk तब आपके पास भविष्य होगा, जो registerOnCompleteCallback()समाप्त होने के बाद पूरा होता है। इसके अलावा, यह वापस नहीं करता है Future[Response]। इसके Future[registerOnCompleteCallback() return type]बदले लौटता है ।
एवगेनी वेरिटेनिकोव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.