फ्यूचर और प्रॉमिस में क्या अंतर है?


274

बीच क्या अंतर है Futureऔर Promise?
वे दोनों भविष्य के परिणामों के लिए एक प्लेसहोल्डर की तरह काम करते हैं, लेकिन मुख्य अंतर कहां है?


99
आप Promiseइसे बनाकर रख सकते हैं। जब कोई दूसरा आपको एक वादा करता है तो आपको यह देखने के लिए इंतजार करना होगा कि क्या वे इसे सम्मानित करते हैंFuture
केविन राइट

1
विकिपीडिया फ्यूचर्स और वादे
wener

30
मेरे द्वारा पढ़े गए कम से कम सहायक विकिपीडिया लेखों में से एक
फुलुपिघ

जवाबों:


145

इस चर्चा के अनुसार , Promiseअंत CompletableFutureमें जावा 8 में शामिल करने के लिए बुलाया गया है , और इसका जावाडॉक बताते हैं:

एक भविष्य जिसे स्पष्ट रूप से पूरा किया जा सकता है (इसके मूल्य और स्थिति को निर्धारित करना), और एक पूर्णता के रूप में उपयोग किया जा सकता है, आश्रित कार्यों और कार्यों का समर्थन करता है जो इसके पूरा होने पर ट्रिगर होते हैं।

एक उदाहरण सूची में भी दिया गया है:

f.then((s -> aStringFunction(s)).thenAsync(s -> ...);

ध्यान दें कि अंतिम API थोड़ा अलग है लेकिन समान एसिंक्रोनस निष्पादन की अनुमति देता है:

CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);

78
यह आपकी गलती नहीं है, लेकिन यह है कि javadoc निकालने के लिए एक अच्छे तकनीकी लेखक की आवश्यकता है। मेरे पांचवे रीड-थ्रू पर मैं बस सराहना करना शुरू कर सकता हूँ कि यह क्या कहना चाह रहा है ... और मैं वायदा और पहले से ही वादे की समझ के साथ इस पर आता हूं!
चुकंदर-चुकंदर

2
@ चुकंदर-चुकंदर ऐसा लगता है कि अब तक हो चुका है।
हरमन

1
@herman धन्यवाद - मैंने javadoc के अंतिम संस्करण को इंगित करने के लिए लिंक को अपडेट कर दिया है।
अघोरियों

7
@ चुकंदर-चुकंदर आपको असाधारण विधि के लिए डॉक्टर की जाँच करनी चाहिए। यह एक अद्भुत कविता होगी, लेकिन पठनीय प्रलेखन की एक असाधारण विफलता है।
फुलूपिह

4
किसी के लिए भी, @Fulluphigh इस बात का जिक्र कर रहा है । ऐसा लगता है कि इसे हटा दिया गया था / जावा 8 में ओवरहॉल किया गया था
सिडरिक

148

(मैं अब तक के जवाबों से पूरी तरह खुश नहीं हूं, इसलिए यहां मेरा प्रयास है ...)

मुझे लगता है कि केविन राइट की टिप्पणी ( "आप एक वादा कर सकते हैं और इसे बनाए रखने के लिए आप पर निर्भर है। जब कोई व्यक्ति आपसे कोई वादा करता है तो आपको यह देखने के लिए इंतजार करना होगा कि क्या वे इसे भविष्य में सम्मानित करते हैं" ) इसे अच्छी तरह से संक्षेप में प्रस्तुत करता है, लेकिन कुछ स्पष्टीकरण उपयोगी हो सकता है।

वायदा और वादे काफी समान अवधारणाएं हैं, अंतर यह है कि भविष्य एक परिणाम के लिए केवल-पढ़ने वाला कंटेनर है जो अभी तक मौजूद नहीं है, जबकि एक वादा लिखा जा सकता है (आमतौर पर केवल एक बार)। जावा 8 CompletableFuture और अमरूद SettableFuture , वादे के बारे में सोचा जा सकता है क्योंकि उनके मूल्य ( "पूरा") सेट किया जा सकता, लेकिन वे भी भविष्य इंटरफ़ेस को लागू है, इसलिए वहाँ ग्राहक के लिए कोई अंतर नहीं है।

भविष्य का परिणाम "किसी और के द्वारा" सेट किया जाएगा - एक अतुल्यकालिक गणना के परिणाम से। ध्यान दें कि FutureTask - एक क्लासिक भविष्य - को एक कॉल करने योग्य या रननेबल के साथ आरंभीकृत किया जाना चाहिए, कोई भी तर्क-वितर्क नहीं है, और Future और FutureTask दोनों ही बाहर से पढ़े जाते हैं (FutureTask के सेट के तरीके सुरक्षित हैं)। मूल्य को अंदर से गणना के परिणाम पर सेट किया जाएगा।

दूसरी ओर, किसी भी वादे का परिणाम "आप" (या वास्तव में किसी के द्वारा) सेट किया जा सकता है क्योंकि इसमें एक सार्वजनिक सेट विधि है। दोनों पूर्णरूपेण सिलाई और SettableFuture किसी भी काम के बिना बनाया जा सकता है, और उनके मूल्य किसी भी समय सेट किया जा सकता है। आप ग्राहक कोड को एक वादा भेजते हैं, और बाद में इसे अपनी इच्छानुसार पूरा करते हैं।

ध्यान दें कि कंप्लीटटेबल सीवन एक "शुद्ध" वादा नहीं है, इसे फ्यूचरटैस्क की तरह एक कार्य के साथ शुरू किया जा सकता है, और इसकी सबसे उपयोगी विशेषता प्रसंस्करण चरणों की असंबंधित चेनिंग है।

यह भी ध्यान दें कि एक वादा भविष्य का उपप्रकार नहीं होता है और इसे एक ही वस्तु होने की आवश्यकता नहीं होती है। स्काला में एक भविष्य की वस्तु एक अतुल्यकालिक गणना या एक अलग वादा वस्तु द्वारा बनाई गई है । C ++ में स्थिति समान है: वादा वस्तु का उपयोग निर्माता और भविष्य की वस्तु उपभोक्ता द्वारा किया जाता है। इस पृथक्करण का लाभ यह है कि ग्राहक भविष्य का मूल्य निर्धारित नहीं कर सकता है।

स्प्रिंग और EJB 3.1 दोनों में एक AsyncResult क्लास है, जो स्काला / C ++ वादों के समान है। AsyncResult फ्यूचर को कार्यान्वित करता है, लेकिन यह वास्तविक भविष्य नहीं है: स्प्रिंग / EJB में एसिंक्रोनस तरीके कुछ पृष्ठभूमि जादू के माध्यम से एक अलग, केवल-पढ़ने के लिए फ्यूचर ऑब्जेक्ट लौटाते हैं, और परिणाम का उपयोग करने के लिए क्लाइंट द्वारा इस दूसरे "वास्तविक" भविष्य का उपयोग किया जा सकता है।


116

मुझे पता है कि पहले से ही एक स्वीकृत उत्तर है, लेकिन फिर भी मैं अपने दो सेंट जोड़ना चाहूंगा:

TLDR: भविष्य और वादा एक अतुल्यकालिक ऑपरेशन के दो पक्ष हैं: उपभोक्ता / कॉलर बनाम निर्माता / कार्यान्वयनकर्ता

एक अतुल्यकालिक एपीआई विधि के कॉलर के रूप में , आपको Futureगणना के परिणाम के रूप में एक हैंडल मिलेगा । आप उदाहरण get()के लिए गणना पूरी होने और परिणाम प्राप्त करने के लिए प्रतीक्षा करने के लिए उस पर कॉल कर सकते हैं ।

अब सोचें कि यह एपीआई विधि वास्तव में कैसे लागू की गई है: कार्यान्वयनकर्ता को Futureतुरंत वापस लौटना चाहिए । गणना पूरा होते ही वे उस भविष्य को पूरा करने के लिए जिम्मेदार होते हैं (जो उन्हें पता होगा क्योंकि यह प्रेषण तर्क को लागू कर रहा है ;-))। वे ऐसा करने के लिए a Promise/ CompletableFutureका उपयोग करेंगे : निर्माण और CompletableFutureतुरंत वापस , और complete(T result)एक बार गणना करने के बाद कॉल करें ।


1
क्या इसका तात्पर्य यह है कि एक वादा हमेशा भविष्य का एक उपवर्ग है, और यह कि भविष्य की लेखन क्षमता केवल प्रकार से अस्पष्ट है?
devios1

मुझे नहीं लगता कि यह निहित है । कार्यान्वयन-वार, यह अक्सर मामला होगा (उदाहरण के लिए जावा, स्काला में)।
राहेल लूथी

74

मैं एक उदाहरण दूंगा कि प्रॉमिस क्या है और फ्यूचर के विपरीत किसी भी समय इसका मूल्य कैसे निर्धारित किया जा सकता है, कौन सा मूल्य केवल पठनीय है।

मान लीजिए आपके पास एक माँ है और आप उससे पैसे मांगते हैं।

// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
Supplier<Integer> momsPurse = ()-> {

        try {
            Thread.sleep(1000);//mom is busy
        } catch (InterruptedException e) {
            ;
        }

        return 100;

    };


ExecutorService ex = Executors.newFixedThreadPool(10);

CompletableFuture<Integer> promise =  
CompletableFuture.supplyAsync(momsPurse, ex);

// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));

// But your father interferes and generally aborts mom's plans and 
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse 
// (remember the Thread.sleep(...)) :
promise.complete(10); 

उस का आउटपुट है:

Thank you mom for $10

माँ का वादा बनाया गया था, लेकिन कुछ "पूरा होने" की घटना का इंतजार कर रहा था।

CompletableFuture<Integer> promise...

आपने इस तरह का आयोजन किया, उसके वादे को स्वीकार किया और अपनी माँ को धन्यवाद देने के लिए अपनी योजनाओं की घोषणा की:

promise.thenAccept...

इस क्षण माँ ने अपना पर्स खोलना शुरू किया ... लेकिन बहुत धीमी ...

और पिता ने बहुत तेजी से हस्तक्षेप किया और अपनी माँ के बदले वादा पूरा किया:

promise.complete(10);

क्या आपने एक निष्पादक पर ध्यान दिया है जिसे मैंने स्पष्ट रूप से लिखा है?

दिलचस्प बात यह है कि, यदि आप इसके बजाय (कॉमनपूल) डिफॉल्ट इम्प्लिमेंट एक्ज़ीक्यूटर का उपयोग करते हैं और पिता घर पर नहीं हैं, लेकिन केवल माँ "उनके" धीमे पर्स "के साथ हैं, तो उनका वादा केवल पूरा होगा, अगर प्रोग्राम को मॉम की तुलना में अधिक समय तक रहने के लिए पैसे प्राप्त करने की आवश्यकता है पर्स।

डिफ़ॉल्ट निष्पादक एक "डेमॉन" की तरह काम करता है और सभी वादे पूरे होने का इंतजार नहीं करता है। मुझे इस तथ्य का अच्छा विवरण नहीं मिला है ...


8
इसे पढ़ने में बहुत मज़ा आता है! मुझे नहीं लगता कि मैं भविष्य को भूल सकता हूं और वादा करता हूं।
user1532146

2
इसे उत्तर के रूप में स्वीकार किया जाना चाहिए। इसकी सिर्फ एक कहानी पढ़ना पसंद है। धन्यवाद @Vladimir
Phillen

धन्यवाद @ वल्दिरमिर
intvprep

9

निश्चित नहीं है कि यह एक उत्तर हो सकता है लेकिन जैसा कि मैंने देखा कि दूसरों ने किसी के लिए क्या कहा है, ऐसा लग सकता है कि आपको इन दोनों अवधारणाओं के लिए दो अलग-अलग अमूर्त की आवश्यकता है ताकि उनमें से एक ( Future) केवल दूसरे का केवल पढ़ने के लिए ( Promise) ... लेकिन वास्तव में इसकी जरूरत नहीं है।

उदाहरण के लिए एक नज़र डालें कि कैसे जावास्क्रिप्ट में वादों को परिभाषित किया जाता है:

https://promisesaplus.com/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

ध्यान केंद्रित करने की thenविधि का उपयोग कर की तरह है:

asyncOp1()
.then(function(op1Result){
  // do something
  return asyncOp2();
})
.then(function(op2Result){
  // do something more
  return asyncOp3();
})
.then(function(op3Result){
  // do something even more
  return syncOp4(op3Result);
})
...
.then(function(result){
  console.log(result);
})
.catch(function(error){
  console.log(error);
})

जो तुल्यकालिक की तरह दिखने के लिए अतुल्यकालिक गणना करता है:

try {
  op1Result = syncOp1();
  // do something
  op1Result = syncOp2();
  // do something more
  op3Result = syncOp3();
  // do something even more
  syncOp4(op3Result);
  ...
  console.log(result);
} catch(error) {
  console.log(error);
}

जो बहुत अच्छा है। (नहीं के रूप में के रूप में शांत async- वेट लेकिन async- वेट सिर्फ बॉयलरप्लेट निकालता है .... फिर (फ़ंक्शन (परिणाम) {.... इससे)।

और वास्तव में उनके अमूर्त वादे निर्माता के रूप में बहुत अच्छा है

new Promise( function(resolve, reject) { /* do it */ } );

आपको दो कॉलबैक प्रदान करने की अनुमति देता है जिसका उपयोग या तो Promiseसफलतापूर्वक या किसी त्रुटि के साथ किया जा सकता है । ताकि केवल निर्माण करने वाला कोड ही Promiseइसे पूरा कर सके और पहले से निर्मित Promiseवस्तु प्राप्त करने वाले कोड में रीड-ओनली व्यू हो।

इनहेरिटेंस के साथ उपरोक्त प्राप्त किया जा सकता है यदि संकल्प और अस्वीकार संरक्षित तरीके हैं।


4
+1। यह इस प्रश्न का सही उत्तर है। CompletableFutureकुछ समानता हो सकती है, Promiseलेकिन यह अभी भी एक नहीं हैPromise , क्योंकि जिस तरह से इसका उपभोग करने का इरादा है वह अलग है: Promiseकॉल करने से परिणाम का उपभोग होता है then(function), और निर्माता द्वारा कॉल के तुरंत बाद फ़ंक्शन को निर्माता के संदर्भ में निष्पादित किया जाता है।resolve । एक Futureपरिणाम को कॉल करके उपभोग किया जाता है getजिसके कारण उपभोक्ता थ्रेड इंतजार करता है जब तक कि निर्माता थ्रेड ने मान उत्पन्न नहीं किया है, तब इसे उपभोक्ता में संसाधित करता है। Futureस्वाभाविक रूप से
बहुप्रचलित है

5
... यह Promiseकेवल एक ही धागे के साथ उपयोग करना पूरी तरह से संभव है (और वास्तव में यह सटीक वातावरण है जिसे वे मूल रूप से डिजाइन किए गए थे: जावास्क्रिप्ट अनुप्रयोगों में आमतौर पर केवल एक ही धागा होता है, इसलिए आप वहां लागू नहीं कर सकते हैंFuture )। Promiseइसलिए की तुलना में बहुत अधिक हल्का और कुशल है Future, लेकिन Futureऐसी परिस्थितियों में सहायक हो सकता है जो अधिक जटिल हैं और थ्रेड्स के बीच सहयोग की आवश्यकता होती है जो आसानी से Promiseएस का उपयोग करके व्यवस्थित नहीं किया जा सकता है । संक्षेप में कहें : Promiseएक पुश मॉडल है, जबकि Futureएक पुल मॉडल है (cf Iterable vs Observable)
Periata Breatta

@PeriataBreatta एकल-थ्रेडेड वातावरण में भी, वादे को पूरा करने वाला कुछ होना चाहिए (जो आम तौर पर एक अलग धागे के रूप में रन की तरह होता है, उदाहरण के लिए, ए XMLHttpRequest)। मैं दक्षता के दावे पर विश्वास नहीं करता, क्या आपके पास कुछ आंकड़े हैं? +++ ने कहा, बहुत अच्छी व्याख्या।
मआर्टिनस

1
@maaartinus - हाँ, कुछ वादे को पूरा करना चाहिए, लेकिन यह (और कई मामलों में वास्तव में) एक शीर्ष स्तर के लूप का उपयोग करके किया जाता है जो बाहरी राज्य में परिवर्तन के लिए मतदान करता है और जो भी वादे किए गए कार्यों से संबंधित होते हैं। दक्षता के अनुसार, मेरे पास विशेष रूप से वादों के लिए कोई ठोस आंकड़ा नहीं है, लेकिन ध्यान दें कि getएक अनसुलझे कॉल पर Futureजरूरी 2 थ्रेड संदर्भ स्विच शामिल होंगे, जिनकी कम से कम कुछ साल पहले हमें लगभग 50 की आवश्यकता थी ।
पेरियाटा ब्रीटाटा

@PeriataBreatta वास्तव में आपकी टिप्पणी को स्वीकृत समाधान होना चाहिए। मैं तुम्हारी तरह एक स्पष्टीकरण (पुल / पुश, सिंगल / मल्टी-थ्रेड) की तलाश में था।
थॉमस जैकब

5

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


2

फ्यूचर इंटरफेस में कोई सेट विधि नहीं है, केवल विधि प्राप्त करें, इसलिए यह केवल पढ़ने के लिए है। कंप्लीटटेबल सीमेंट के बारे में, यह लेख शायद सहायक हो। completablefuture

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.