Clojure ฟิวเจอร์สและสัญญาแตกต่างกันอย่างไร?


86

ทั้งฟิวเจอร์สและสัญญาจะปิดกั้นจนกว่าพวกเขาจะคำนวณมูลค่าของมันแล้วอะไรคือความแตกต่างระหว่างพวกเขา?


8
ฉันไม่แน่ใจว่าทำไมถึง -1 ในคำถามหรือเป็นคำถามที่คุณไม่รู้คำตอบก่อนที่จะถามสิ่งที่ไม่ดีในตอนนี้?
เพียงแค่ความคิดเห็นที่ถูกต้องของฉัน

ฉันไม่ได้ -1 คำตอบใด ๆ ?? เราจะบอกได้อย่างไรว่าใครใส่ -1 ใน quesiton หรือคำตอบ?
yazz.com

คุณและฉันทำไม่ได้ Zubair ฉันแค่อยากรู้ว่าใครใส่ -1 ในคำถามของคุณเนื่องจากเป็นคำถามที่สมเหตุสมผลอย่างยิ่งที่จะถามและแน่นอนว่าเป็นหัวข้อสำหรับ SO
เพียงแค่ความคิดเห็นที่ถูกต้องของฉัน

คำตอบ:


54

การตอบในเงื่อนไข Clojure นี่คือตัวอย่างบางส่วนจากscreencast ของ Sean Devlin :

(def a-promise (promise))
(deliver a-promise :fred)

(def f (future (some-sexp)))
(deref f)

โปรดทราบว่าในสัญญาคุณจะส่งมอบค่าที่คุณเลือกอย่างชัดเจนในการคำนวณ:fredในภายหลัง ( ในกรณีนี้) ในทางกลับกันอนาคตกำลังถูกเผาผลาญในสถานที่เดียวกับที่สร้างขึ้น some-exprมีการเปิดตัวคงจะอยู่เบื้องหลังและการคำนวณในตีคู่ (ในที่สุด) แต่ถ้ามันยังคงอยู่ unevaluated ตามเวลาที่มันมีการเข้าถึงบล็อกด้ายจนกว่าจะสามารถใช้ได้


แก้ไขเพื่อเพิ่ม

เพื่อช่วยแยกความแตกต่างระหว่างคำสัญญากับอนาคตให้สังเกตสิ่งต่อไปนี้:

สัญญา

  1. คุณสร้างไฟล์promise. ขณะนี้วัตถุสัญญานั้นสามารถส่งผ่านไปยังเธรดใดก็ได้
  2. คุณดำเนินการคำนวณต่อไป สิ่งเหล่านี้อาจเป็นการคำนวณที่ซับซ้อนมากซึ่งเกี่ยวข้องกับผลข้างเคียงการดาวน์โหลดข้อมูลการป้อนข้อมูลของผู้ใช้การเข้าถึงฐานข้อมูลคำสัญญาอื่น ๆ ไม่ว่าคุณจะต้องการอะไรก็ตาม รหัสจะมีลักษณะเหมือนกับรหัสเมนไลน์ของคุณในโปรแกรมใด ๆ
  3. เมื่อคุณทำเสร็จแล้วคุณจะได้deliverผลลัพธ์ไปยังวัตถุสัญญานั้น
  4. รายการใด ๆ ที่พยายามทำderefตามสัญญาก่อนที่คุณจะคำนวณเสร็จจะถูกบล็อกจนกว่าคุณจะทำเสร็จ เมื่อคุณทำเสร็จและคุณได้deliverแก้ไขสัญญาแล้วคำสัญญาจะไม่ปิดกั้นอีกต่อไป

อนาคต

  1. คุณสร้างอนาคตของคุณ อนาคตของคุณส่วนหนึ่งคือนิพจน์สำหรับการคำนวณ
  2. อนาคตอาจดำเนินการพร้อมกันหรือไม่ก็ได้ สามารถกำหนดเธรดได้อาจมาจากพูล มันทำได้แค่รอและไม่ทำอะไรเลย จากมุมมองของคุณคุณไม่สามารถบอกได้
  3. ในบางจุดคุณ (หรือหัวข้ออื่น) derefเป็นอนาคต หากการคำนวณเสร็จสมบูรณ์แล้วคุณจะได้รับผลลัพธ์ของมัน หากยังไม่เสร็จสมบูรณ์คุณจะบล็อกจนกว่าจะมี (สันนิษฐานว่าหากยังไม่เริ่มทำงานแสดงderefว่าเริ่มดำเนินการแล้ว แต่ก็ไม่รับประกันเช่นกัน)

ในขณะที่คุณสามารถทำให้นิพจน์ในอนาคตมีความซับซ้อนเหมือนกับโค้ดที่เป็นไปตามการสร้างคำสัญญา แต่ก็น่าสงสัยว่าเป็นที่พึงปรารถนา ซึ่งหมายความว่าฟิวเจอร์สเหมาะกับการคำนวณที่รวดเร็วและสามารถทำงานในเบื้องหลังได้มากขึ้นในขณะที่สัญญานั้นเหมาะกับเส้นทางการดำเนินการที่มีขนาดใหญ่และซับซ้อน ดูเหมือนสัญญาในแง่ของการคำนวณที่มีอยู่มีความยืดหยุ่นมากขึ้นเล็กน้อยและมุ่งเน้นไปที่ผู้สร้างสัญญาที่ทำงานและเธรดอื่นที่เกี่ยวกับการเก็บเกี่ยว ฟิวเจอร์สมุ่งเน้นไปที่การเริ่มต้นเธรดโดยอัตโนมัติ (โดยไม่มีค่าใช้จ่ายที่น่าเกลียดและเกิดข้อผิดพลาดได้ง่าย) และดำเนินต่อไปกับสิ่งอื่น ๆ จนกว่าคุณ - เธรดต้นทาง - ต้องการผลลัพธ์


แต่คุณสามารถมีช่วงการคำนวณใด ๆ ก็ได้จนกว่าสัญญาหรืออนาคตจะเสร็จสิ้น เช่น: (@a + @b) จะทำงานเหมือนกันทั้งอนาคตและสัญญา
yazz.com

2
คำสัญญาช่วยให้ฉันมีความยืดหยุ่นมากขึ้น ฉันสร้างสัญญา ฉันส่งสัญญานั้นไปยังเธรดอื่น จากนั้นฉันสามารถทำการคำนวณที่ซับซ้อนมากมายรวมถึงการรอ I / O การดาวน์โหลดข้อมูลจากอินเทอร์เน็ตการรอการป้อนข้อมูลของผู้ใช้ ฯลฯ เมื่อทุกอย่างเสร็จสิ้นฉันจะให้คำมั่นสัญญาพร้อมค่าผลลัพธ์ อนาคตครอบคลุม S-expression หนึ่งรายการ ฉันเดาได้ว่าน่าจะเป็น S-expression ที่ซับซ้อนมาก แต่มันคงจะ ... แข็งไปหน่อย นอกจากนี้อนาคตจะทำงานโดยอัตโนมัติในเธรด (หรือพูล) การทำเช่นเดียวกันในคำสัญญาจะหมายถึงการทำงานมากขึ้น
เพียงแค่ความคิดเห็นที่ถูกต้องของฉัน

FWIW เนื่องจาก s-expression เดียวสามารถเรียกไปยังพา ธ โค้ดที่กำหนดเองได้จึงไม่จำเป็นต้องเกี่ยวกับจำนวนโค้ดที่คุณสามารถอัดเข้าไปในนิพจน์ได้ ดังนั้นแทนที่จะพูดคำสัญญาว่า "ยืดหยุ่นกว่า" ฉันจะบอกว่ามันมีจุดประสงค์ที่แตกต่างกัน ไม่งั้นทำไมต้องมีทั้งสองอย่าง?
Geoff

2
สำหรับการบันทึกเนื้อหาของการfutureโทรสามารถรวม N sexprs ได้
vemv

คำอธิบายนี้ควรเป็นส่วนหนึ่งของ Clojure Doc
Piyush Katariya

25

ทั้งอนาคตและสัญญาเป็นกลไกในการสื่อสารผลลัพธ์ของการคำนวณแบบอะซิงโครนัสจาก Producer ไปยังผู้บริโภค

ในกรณีของอนาคตการคำนวณจะถูกกำหนดในช่วงเวลาของการสร้างอนาคตและการดำเนินการแบบ async จะเริ่มต้น "ASAP" นอกจากนี้ยัง "รู้" วิธีสร้างการคำนวณแบบอะซิงโครนัส

ในกรณีที่สัญญาคำนวณมันเวลาเริ่มต้นและ [ไปได้] ตรงกันภาวนาจะหลุดพ้นจากกลไกการส่งมอบ เมื่อผลการคำนวณพร้อมใช้งาน Producer ต้องเรียกdeliverอย่างชัดเจนซึ่งหมายความว่า Producer จะควบคุมเมื่อผลลัพธ์พร้อมใช้งาน

สำหรับสัญญา Clojure ทำผิดการออกแบบโดยใช้วัตถุเดียวกัน (ผลจากการpromiseโทร) ทั้งการผลิต ( deliver) และบริโภค ( deref) ผลจากการคำนวณ นี่เป็นสองความสามารถที่แตกต่างกันมากและควรได้รับการปฏิบัติเช่นนี้


@oskarkv สมมติว่าคุณสร้างสัญญาและให้กับลูกค้า 3 ราย ไม่มีสิ่งใดที่ป้องกันไม่ให้ไคลเอนต์รายใดรายหนึ่งแก้ไขด้วยผลการหลอกลวงและส่งสัญญาณไปยังไคลเอนต์อื่นอีกสองราย แถมคุณจะไม่สามารถแก้ไขคำสัญญานี้ได้อีกต่อไป ในทางตรงกันข้ามหากคุณมีคู่สัญญา + ตัวแก้ไขให้สัญญากับลูกค้าของคุณและคอยแก้ปัญหาด้วยตัวคุณเองสถานการณ์นี้จะเป็นไปไม่ได้ สำหรับข้อมูลเพิ่มเติมข้อความค้นหาที่แนะนำ ได้แก่ "การควบคุมการเข้าถึงตามความสามารถ" และ "การรักษาความปลอดภัยตามความสามารถ"
Dimagog

1
ฉันไม่แน่ใจว่าการรักษาความปลอดภัยการเชื่อมต่อกับประเภทการอ้างอิงแบบธรรมดานั้นหรือไม่ (ตรวจสอบโดยนัย) ตามที่promiseสะดวก ผู้บริโภคที่ 'ชั่ว' หายาก ไม่มีอะไรหยุดคุณจากการสร้างสิ่งที่เป็นนามธรรมของคุณเองนอกเหนือจากคำสัญญา
vemv

8
ไม่เกี่ยวกับความปลอดภัย แต่เกิดขึ้นเช่นกันที่การเขียนโปรแกรมตามความสามารถมักอธิบายเกี่ยวกับความปลอดภัย นี่คือทั้งหมดที่เกี่ยวกับความถูกต้องของรหัส คำที่มักใช้คือ "ถูกต้องโดยการก่อสร้าง" และคำถามคือ "คุณสามารถสร้างโปรแกรมที่ไม่ถูกต้อง" ได้หรือไม่? ไม่ได้ตั้งใจ แต่เป็นเรื่องบังเอิญ ด้วยวัตถุ Promise เดียวคุณสามารถทำได้ในขณะที่คุณไม่สามารถแยกวัตถุสองชิ้นได้
Dimagog

ไม่มีอะไรหยุดคุณจากการคืนสัญญาที่ไม่สามารถส่งมอบได้หากนั่นคือสิ่งที่คุณต้องการ: (defn undeliverable-promise [] (let [p (promise)] (reify clojure.lang.IDeref (deref [_] (deref p)) clojure.lang.IBlockingDeref (deref [_ ms val] (deref p ms val)) clojure.lang.IPending (isRealized [_] (.isRealized p)) clojure.lang.IFn (invoke [_ _] nil))))
tapichu

การชี้ให้เห็นความแตกต่างของวิธีการแยกกลไกการคำนวณทำให้โพสต์นี้มีคำอธิบายที่กระชับจริงๆ ขอบคุณ!
synthomat

3

มีคำตอบที่ยอดเยี่ยมอยู่แล้วจึงเพิ่มเฉพาะสรุป "วิธีใช้" เท่านั้น:

ทั้งสอง

การสร้างสัญญาหรืออนาคตจะส่งคืนข้อมูลอ้างอิงทันที การอ้างอิงนี้บล็อกบน @ / deref จนกว่าจะมีการจัดเตรียมผลลัพธ์ของการคำนวณโดยเธรดอื่น

อนาคต

เมื่อสร้างอนาคตคุณต้องจัดหางานซิงโครนัสที่ต้องทำ มันดำเนินการในเธรดจากพูลที่ไม่ถูกผูกไว้โดยเฉพาะ

สัญญา

คุณไม่มีข้อโต้แย้งใด ๆ เมื่อสร้างสัญญา การอ้างอิงที่ควรได้รับการส่งผ่านไปยังคนอื่น ๆ ของผู้ใช้ด้ายที่จะdeliverส่งผลให้


1

ใน Clojure, promise, futureและdelayมีสัญญาเหมือนวัตถุ ทั้งหมดนี้แสดงถึงการคำนวณที่ลูกค้าสามารถรอได้โดยใช้deref(หรือ@) ไคลเอนต์ใช้ผลลัพธ์ซ้ำเพื่อไม่ให้การคำนวณทำงานหลายครั้ง

พวกเขาแตกต่างกันในวิธีการคำนวณ:

  • futureจะเริ่มต้นการคำนวณในเธรดผู้ปฏิบัติงานอื่น derefจะบล็อกจนกว่าผลลัพธ์จะพร้อม

  • delayจะดำเนินการคำนวณอย่างเฉื่อยชาเมื่อใช้ครั้งแรกของลูกค้าหรือderefforce

  • promisedeliverมีความยืดหยุ่นมากที่สุดเป็นผลของมันจะถูกส่งไปในทางที่กำหนดเองโดยใช้ คุณสามารถใช้มันเมื่อค่าfutureหรือdelayตรงกับกรณีการใช้งานของคุณ


-4

ประการแรก a PromiseคือFuture. ฉันคิดว่าคุณต้องการทราบความแตกต่างระหว่าง a PromiseและFutureTask.

A Futureหมายถึงค่าที่ยังไม่เป็นที่รู้จักในปัจจุบัน แต่จะทราบในอนาคต

A FutureTaskแสดงถึงผลลัพธ์ของการคำนวณที่จะเกิดขึ้นในอนาคต (อาจจะเป็นเธรดพูล) เมื่อคุณพยายามเข้าถึงผลลัพธ์หากการคำนวณยังไม่เกิดขึ้นระบบจะบล็อก มิฉะนั้นผลลัพธ์จะถูกส่งกลับทันที ไม่มีฝ่ายอื่นที่เกี่ยวข้องในการคำนวณผลลัพธ์เนื่องจากคุณได้ระบุการคำนวณไว้ล่วงหน้า

A Promiseหมายถึงผลลัพธ์ที่ผู้ให้สัญญาจะส่งมอบให้แก่ผู้รับสัญญาในอนาคต ในกรณีนี้คุณคือผู้ให้สัญญาและผู้ให้สัญญาคือผู้ที่ให้Promiseวัตถุแก่คุณ คล้ายกับFutureTaskถ้าคุณพยายามที่จะเข้าถึงผลก่อนที่จะPromiseได้รับการเติมเต็มจะได้รับการปิดกั้นจน promiser Promiseตอบสนอง เมื่อPromiseสำเร็จแล้วคุณจะได้รับค่าเดียวกันเสมอและทันที ซึ่งแตกต่างจาก a FutureTaskมีอีกฝ่ายที่เกี่ยวข้องที่นี่ซึ่งเป็นผู้สร้างไฟล์Promise. Promiseที่บุคคลอื่นเป็นผู้รับผิดชอบสำหรับการทำการคำนวณและการตอบสนอง

ในแง่นั้น a FutureTaskคือPromiseคุณสร้างขึ้นเพื่อตัวเอง


คุณแน่ใจหรือว่าคำสัญญาคืออนาคต? ฉันไม่พบว่ามันใช้อินเทอร์เฟซ github.com/richhickey/clojure/blob/…
Mikael Sundberg

ขอโทษฉันป้อนข้อมูลผิดพลาด คำถามของฉันเปลี่ยนไป
Mikael Sundberg

คำตอบของฉันอยู่ในความหมายทั่วไปไม่ใช่ใน Clojure ที่เฉพาะเจาะจง
Abhinav Sarkar

9
การตอบคำถามเกี่ยวกับ Clojure ด้วยโค้ด Java ดูเหมือนจะค่อนข้างแปลก
เพียงแค่ความคิดเห็นที่ถูกต้องของฉัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.