ความแตกต่างระหว่างFuture
และPromise
คืออะไร
พวกเขาทั้งสองทำตัวเหมือนเป็นตัวแทนสำหรับผลลัพธ์ในอนาคต แต่ความแตกต่างหลักอยู่ที่ไหน
ความแตกต่างระหว่างFuture
และPromise
คืออะไร
พวกเขาทั้งสองทำตัวเหมือนเป็นตัวแทนสำหรับผลลัพธ์ในอนาคต แต่ความแตกต่างหลักอยู่ที่ไหน
คำตอบ:
ตามที่การสนทนานี้ , Promise
ที่สุดก็ได้รับการเรียกว่าCompletableFuture
สำหรับการรวมใน Java 8 และJavadoc มันอธิบายว่า:
อนาคตที่อาจจะเสร็จสมบูรณ์อย่างชัดเจน (การตั้งค่าและสถานะของมัน) และอาจถูกใช้เป็น CompletionStage ซึ่งรองรับฟังก์ชั่นที่ต้องพึ่งพาและการกระทำที่ก่อให้เกิดความสำเร็จ
ตัวอย่างมีให้ในรายการ:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
โปรดทราบว่า API ขั้นสุดท้ายนั้นแตกต่างกันเล็กน้อย แต่อนุญาตการดำเนินการแบบอะซิงโครนัสที่คล้ายกัน
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
(ฉันไม่พอใจกับคำตอบทั้งหมดดังนั้นนี่คือความพยายามของฉัน ... )
ฉันคิดว่าความคิดเห็นของ Kevin Wright ( "คุณสามารถทำสัญญาและมันก็ขึ้นอยู่กับคุณที่จะเก็บไว้เมื่อมีคนอื่นทำให้คุณสัญญาคุณต้องรอเพื่อดูว่าพวกเขาให้เกียรติในอนาคต" ) สรุปได้ค่อนข้างดี แต่บางคน คำอธิบายมีประโยชน์
ฟิวเจอร์และสัญญาเป็นแนวคิดที่คล้ายกันสวยความแตกต่างคืออนาคตเป็นที่บรรจุแบบอ่านอย่างเดียวสำหรับผลลัพธ์ที่ยังไม่มีในขณะที่สัญญาสามารถเขียนได้ (ปกติเพียงครั้งเดียวเท่านั้น) Java 8 CompletableFutureและ Guava SettableFutureสามารถถูกมองว่าเป็นสัญญาได้เพราะค่าของมันสามารถตั้งค่าได้ ("เสร็จสมบูรณ์") แต่พวกเขายังใช้ส่วนต่อประสานในอนาคต
ผลลัพธ์ของอนาคตจะถูกกำหนดโดย "บุคคลอื่น" - โดยผลลัพธ์ของการคำนวณแบบอะซิงโครนัส โปรดทราบว่าFutureTask - อนาคตคลาสสิก - ต้องเริ่มต้นด้วย Callable หรือ Runnable ไม่มีตัวสร้างแบบไม่มีอาร์กิวเมนต์และทั้ง Future และ FutureTask เป็นแบบอ่านอย่างเดียวจากภายนอก (วิธีการที่ตั้งของ FutureTask ได้รับการป้องกัน) ค่าจะถูกตั้งค่าเป็นผลลัพธ์ของการคำนวณจากภายใน
ในทางกลับกันผลลัพธ์ของคำสัญญาสามารถตั้งค่าได้โดย "คุณ" (หรือในความเป็นจริงโดยใครก็ได้) เพราะมันมีวิธีการตั้งค่าสาธารณะ CompletableFuture และ SettableFuture สามารถสร้างได้โดยไม่ต้องทำงานใด ๆ และสามารถตั้งค่าได้ตลอดเวลา คุณส่งสัญญาไปยังรหัสลูกค้าและปฏิบัติตามในภายหลังตามที่คุณต้องการ
โปรดทราบว่า CompletableFuture ไม่ใช่คำสัญญาที่ "บริสุทธิ์" มันสามารถเริ่มต้นได้ด้วยภารกิจเช่นเดียวกับ FutureTask และคุณลักษณะที่มีประโยชน์ที่สุดคือการผูกมัดขั้นตอนการประมวลผลที่ไม่เกี่ยวข้อง
โปรดทราบว่าสัญญาไม่จำเป็นต้องเป็นประเภทย่อยในอนาคตและไม่จำเป็นต้องเป็นวัตถุเดียวกัน ในกาลาวัตถุในอนาคตจะถูกสร้างขึ้นโดยการคำนวณตรงกันหรือโดยที่แตกต่างกันวัตถุสัญญา ใน C ++ สถานการณ์คล้ายกัน: ผู้ใช้งานจะใช้ออบเจกต์สัญญาและออบเจคในอนาคต ข้อดีของการแยกนี้คือลูกค้าไม่สามารถกำหนดมูลค่าของอนาคตได้
ทั้งSpringและEJB 3.1มีคลาส AsyncResult ซึ่งคล้ายกับสัญญา Scala / C ++ AsyncResult ดำเนินการในอนาคต แต่นี่ไม่ใช่อนาคตที่แท้จริง: วิธีการแบบอะซิงโครนัสใน Spring / EJB จะส่งคืนวัตถุในอนาคตแบบอ่านอย่างเดียวที่แตกต่างกันโดยใช้เวทมนตร์พื้นหลังและไคลเอนต์ในอนาคตที่สอง
ฉันทราบว่ามีคำตอบที่ยอมรับแล้ว แต่ต้องการเพิ่มสองเซนต์ของฉัน:
TLDR: อนาคตและสัญญาที่มีทั้งสองด้านของการดำเนินการไม่ตรงกัน: ผู้บริโภค / โทรเทียบกับผู้ผลิต / implementor
ในฐานะผู้เรียกใช้เมธอดอะซิงโครนัส API คุณจะได้รับFuture
การจัดการกับผลลัพธ์ของการคำนวณ คุณสามารถโทรหาget()
มันเพื่อรอให้การคำนวณเสร็จสมบูรณ์และดึงผลลัพธ์ออกมาได้
ตอนนี้ลองคิดดูว่าวิธีการใช้ API นี้ได้ผลจริง: ผู้ดำเนินการต้องส่งคืนFuture
ทันที พวกเขามีความรับผิดชอบในการทำให้อนาคตนั้นเสร็จสมบูรณ์ทันทีที่การคำนวณเสร็จสิ้น (ซึ่งพวกเขาจะรู้เพราะกำลังใช้ตรรกะการจัดส่ง ;-)) พวกเขาจะใช้ a Promise
/ CompletableFuture
เพื่อทำสิ่งนั้นสร้างและคืนCompletableFuture
ทันทีและเรียกcomplete(T result)
เมื่อการคำนวณเสร็จสิ้น
ฉันจะยกตัวอย่างว่าสัญญาคืออะไรและจะตั้งค่าได้อย่างไรในเวลาใดก็ได้ตรงกันข้ามกับอนาคตซึ่งสามารถอ่านค่าได้เท่านั้น
สมมติว่าคุณมีแม่และขอเงินจากเธอ
// 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);
คุณสังเกตเห็นผู้บริหารที่ฉันเขียนไว้อย่างชัดเจนหรือไม่?
ที่น่าสนใจถ้าคุณใช้ตัวจัดการปริยายแบบปริยายแทน (commonPool) และพ่อไม่ได้อยู่ที่บ้าน แต่มีเพียงแม่ที่มี "กระเป๋าเงินช้า" ดังนั้นสัญญาของเธอก็จะเสร็จสมบูรณ์หากโปรแกรมมีอายุการใช้งานนานกว่าแม่จะต้องได้รับเงินจาก เงิน
ตัวจัดการเริ่มต้นทำหน้าที่เหมือน "daemon" และไม่รอให้สัญญาทั้งหมดเป็นจริง ฉันไม่พบคำอธิบายที่ดีเกี่ยวกับข้อเท็จจริงนี้ ...
ไม่แน่ใจว่านี่อาจเป็นคำตอบ แต่เมื่อฉันเห็นสิ่งที่คนอื่นพูดกับใครบางคนมันอาจดูเหมือนว่าคุณต้องการ abstractions ที่แยกจากกันสำหรับทั้งสองแนวคิดเหล่านี้เพื่อให้หนึ่งในนั้น ( Future
) เป็นเพียงมุมมองแบบอ่านอย่างเดียวPromise
) ... แต่จริงๆแล้วสิ่งนี้ไม่จำเป็น
ตัวอย่างเช่นดูที่สัญญาที่กำหนดไว้ในจาวาสคริปต์:
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-awaitแต่async-awaitเพียงลบ boilerplate .... จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {....จากมัน)
และที่จริงแล้วสิ่งที่เป็นนามธรรมของพวกเขานั้นค่อนข้างดีในฐานะผู้สร้างสัญญา
new Promise( function(resolve, reject) { /* do it */ } );
ช่วยให้คุณสามารถโทรกลับสองครั้งซึ่งสามารถใช้เพื่อดำเนินการให้Promise
สำเร็จหรือมีข้อผิดพลาด ดังนั้นเฉพาะรหัสที่สร้างPromise
สามารถกรอกได้และรหัสที่ได้รับPromise
วัตถุที่สร้างไว้แล้วมีมุมมองแบบอ่านอย่างเดียว
ด้วยการรับมรดกสามารถทำได้หากการแก้ไขและการปฏิเสธเป็นวิธีการป้องกัน
CompletableFuture
อาจมีความคล้ายคลึงกันกับ a Promise
แต่ก็ยังไม่ใช่Promise
เพราะวิธีที่ตั้งใจจะใช้จะแตกต่างกัน: Promise
ผลลัพธ์จะถูกใช้โดยการโทรthen(function)
และฟังก์ชันจะถูกดำเนินการในบริบทของผู้ผลิตทันทีหลังจากที่ผู้ผลิตเรียกresolve
. Future
's ผลมีการบริโภคโดยการโทรget
ซึ่งเป็นสาเหตุของด้ายผู้บริโภคที่จะรอจนกว่าด้ายผลิตได้สร้างมูลค่าแล้วประมวลผลในผู้บริโภค Future
เป็นแบบมัลติเธรดโดยเนื้อแท้ แต่ ...
Promise
เพียงเธรดเดียว (และในความเป็นจริงนั่นคือสภาพแวดล้อมที่แม่นยำซึ่งเดิมถูกออกแบบมาสำหรับ: แอปพลิเคชันจาวาสคริปต์โดยทั่วไปจะมีเธรดเดียวเท่านั้นดังนั้นคุณจึงไม่สามารถติดตั้งได้Future
) Promise
ดังนั้นจึงมีน้ำหนักเบาและมีประสิทธิภาพมากกว่าFuture
แต่Future
จะมีประโยชน์ในสถานการณ์ที่ซับซ้อนและต้องการความร่วมมือระหว่างเธรดที่ไม่สามารถจัดเรียงได้ง่ายโดยใช้Promise
s เพื่อสรุป: Promise
เป็นแบบจำลองการผลักดันในขณะที่Future
เป็นแบบจำลองการดึง (cf Iterable vs Observable)
XMLHttpRequest
) ฉันไม่เชื่อว่าการอ้างสิทธิ์อย่างมีประสิทธิภาพคุณมีตัวเลขบ้างไหม? +++ นั่นคือคำอธิบายที่ดีมาก
get
บนได้รับการแก้ไขFuture
จะจำเป็นต้องเกี่ยวข้องกับหัวข้อที่ 2 สวิทช์บริบทซึ่งอย่างน้อยไม่กี่ปีที่ผ่านมาก็น่าจะเป็นที่จะต้องใช้ประมาณ 50 เรา
สำหรับรหัสลูกค้าสัญญาคือการสังเกตหรือแนบโทรกลับเมื่อผลลัพธ์ที่มีอยู่ในขณะที่ในอนาคตคือการรอผลแล้วดำเนินการต่อ ในทางทฤษฎีอะไรก็ตามที่เป็นไปได้ที่จะทำกับฟิวเจอร์สสิ่งที่สามารถทำได้กับสัญญา แต่เนื่องจากความแตกต่างของรูปแบบ API ผลลัพธ์สำหรับสัญญาในภาษาที่แตกต่างกันทำให้การผูกมัดง่ายขึ้น
ไม่มีวิธีการตั้งค่าในอินเทอร์เฟซในอนาคตเพียงรับเมธอดเท่านั้นดังนั้นจึงเป็นแบบอ่านอย่างเดียว เกี่ยวกับเสร็จสมบูรณ์ในอนาคตบทความนี้อาจมีประโยชน์ completablefuture
Promise
และขึ้นอยู่กับคุณที่จะเก็บมันไว้ เมื่อคนอื่นทำให้คุณสัญญาคุณต้องรอเพื่อดูว่าพวกเขาให้เกียรติในFuture