Hợp đồng tương lai và lời hứa của Clojure khác nhau như thế nào?


86

Cả hợp đồng tương lai và lời hứa đều chặn cho đến khi chúng tính được giá trị của chúng, vậy sự khác biệt giữa chúng là gì?


8
Tôi không chắc tại sao lại có -1 trên câu hỏi, hay là những câu hỏi mà bạn không biết câu trả lời trước khi hỏi những điều tồi tệ?
CHỈ LÀ Ý KIẾN CHÍNH XÁC CỦA TÔI

Tôi không -1 bất kỳ câu trả lời nào ?? Làm thế nào chúng ta có thể biết ai đã đặt -1 vào câu hỏi hoặc câu trả lời?
appshare.co

Bạn và tôi không thể, Zubair. Tôi chỉ tò mò rằng ai đã đặt -1 cho câu hỏi của bạn vì đó là một câu hỏi hoàn toàn hợp lý để hỏi và nó chắc chắn là đúng chủ đề đối với SO.
CHỈ LÀ Ý KIẾN CHÍNH XÁC CỦA TÔI

Câu trả lời:


54

Trả lời bằng thuật ngữ Clojure, đây là một số ví dụ từ video truyền hình của Sean Devlin :

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

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

Lưu ý rằng trong lời hứa, bạn đang cung cấp một cách rõ ràng một giá trị mà bạn chọn trong một lần tính toán sau ( :fredtrong trường hợp này). Mặt khác, tương lai đang được tiêu thụ ở chính nơi mà nó được tạo ra. Có some-exprlẽ nó được khởi chạy ở hậu trường và được tính toán song song (cuối cùng), nhưng nếu nó vẫn không được đánh giá vào thời điểm nó được truy cập vào các khối chuỗi cho đến khi nó có sẵn.


đã chỉnh sửa để thêm

Để giúp phân biệt rõ hơn giữa lời hứa và tương lai, hãy lưu ý những điều sau:

lời hứa

  1. Bạn tạo một promise. Đối tượng hứa đó bây giờ có thể được chuyển đến bất kỳ luồng nào.
  2. Bạn tiếp tục với các phép tính. Đây có thể là những phép tính rất phức tạp liên quan đến các tác dụng phụ, tải dữ liệu, người dùng nhập, truy cập cơ sở dữ liệu, các lời hứa khác - bất cứ điều gì bạn thích. Mã sẽ trông rất giống mã dòng chính của bạn trong bất kỳ chương trình nào.
  3. Khi bạn hoàn thành, bạn có thể deliverkết quả cho đối tượng hứa đó.
  4. Bất kỳ mục nào cố gắng thực hiện dereflời hứa của bạn trước khi bạn hoàn thành tính toán của mình sẽ bị chặn cho đến khi bạn hoàn thành. Khi bạn đã hoàn thành và bạn đã thực hiện deliverlời hứa, thì lời hứa sẽ không còn cản trở nữa.

Tương lai

  1. Bạn tạo ra tương lai của bạn. Một phần của tương lai của bạn là một biểu thức để tính toán.
  2. Tương lai có thể thực hiện đồng thời hoặc không. Nó có thể được gán một chuỗi, có thể từ một nhóm. Nó chỉ có thể chờ đợi và không làm gì cả. Từ quan điểm của bạn, bạn không thể nói .
  3. Tại một số thời điểm bạn (hoặc một chủ đề khác) dereflà tương lai. Nếu phép tính đã hoàn thành, bạn sẽ nhận được kết quả của nó. Nếu nó chưa hoàn thành, bạn chặn cho đến khi nó có. (Có lẽ nếu nó chưa bắt đầu, derefthì nó có nghĩa là nó bắt đầu thực thi, nhưng điều này cũng không được đảm bảo.)

Mặc dù bạn có thể làm cho biểu thức trong tương lai phức tạp như mã sau khi tạo ra một lời hứa, nhưng có lẽ điều đó là mong muốn. Điều này có nghĩa là các hợp đồng tương lai thực sự phù hợp hơn với các tính toán nhanh, có thể chạy nền trong khi các hứa hẹn thực sự phù hợp hơn với các đường dẫn thực thi lớn và phức tạp. Ngoài ra, các lời hứa dường như, về mặt tính toán có sẵn, linh hoạt hơn một chút và hướng đến người tạo lời hứa đang thực hiện công việc và một chuỗi khác gặt hái mùa màng. Các hợp đồng tương lai có xu hướng tự động bắt đầu một chuỗi (không có chi phí xấu và dễ xảy ra lỗi) và tiếp tục với những thứ khác cho đến khi bạn - chuỗi ban đầu - cần kết quả.


Nhưng bạn có thể có bất kỳ khối caluclation nào cho đến khi kết thúc một lời hứa HOẶC một tương lai. ví dụ: (@a + @b) sẽ làm việc cùng với cả một tương lai và một lời hứa
appshare.co

2
Với tôi, một lời hứa cho phép linh hoạt hơn. Tôi tạo ra một lời hứa. Tôi chuyển lời hứa đó sang một chủ đề khác. Sau đó, tôi có thể thực hiện nhiều phép tính phức tạp bao gồm chờ I / O, tải dữ liệu từ Internet, chờ nhập liệu của người dùng, v.v. Khi tất cả hoàn thành, tôi đưa ra lời hứa với giá trị kết quả. Tương lai bao hàm một biểu thức S. Tôi đoán nó có thể là một biểu thức chữ S rất, rất phức tạp, nhưng nó sẽ hơi ... cứng nhắc ở đó. Ngoài ra, tương lai sẽ tự động hoạt động trong một chuỗi (hoặc nhóm). Làm điều tương tự trong một lời hứa sẽ có nghĩa là phải làm nhiều việc hơn.
CHỈ LÀ Ý KIẾN CHÍNH XÁC CỦA TÔI

FWIW vì một biểu thức s đơn lẻ có thể là một lệnh gọi đến một đường dẫn mã tùy ý, nó không nhất thiết về việc bạn có thể nhồi nhét bao nhiêu mã vào biểu thức. Vì vậy, thay vì nói một lời hứa là "linh hoạt hơn", tôi muốn nói rằng mục đích của nó đơn giản là khác. Nếu không, tại sao có cả hai?
Geoff

2
Chỉ đối với bản ghi, nội dung futurecuộc gọi có thể bao gồm N sexprs.
vemv 29/12/12

Cách giải thích này nên là một phần của Clojure Doc
Piyush Katariya

25

Cả Tương lai và Hứa hẹn đều là cơ chế truyền đạt kết quả tính toán không đồng bộ từ Nhà sản xuất đến (các) Người tiêu dùng.

Trong trường hợp Tương lai , tính toán được xác định tại thời điểm tạo Tương lai và quá trình thực thi không đồng bộ bắt đầu "ASAP". Nó cũng "biết" cách sinh ra một phép tính không đồng bộ.

Trong trường hợp của Promise các tính toán , nó thời gian bắt đầu và [có thể] không đồng bộ gọi được tách riêng từ cơ chế giao hàng. Khi có kết quả tính toán, Producer phải gọi delivermột cách rõ ràng, điều này cũng có nghĩa là Producer kiểm soát khi nào có kết quả.

Đối với Promises, Clojure mắc lỗi thiết kế khi sử dụng cùng một đối tượng (kết quả của promiselệnh gọi) để tạo ra ( deliver) và tiêu thụ ( deref) kết quả của tính toán . Đây là hai khả năng rất khác biệt và nên được xử lý như vậy.


@oskarkv Giả sử bạn đã tạo một lời hứa và đưa nó cho 3 khách hàng. Không có gì ngăn cản một trong những máy khách giải quyết nó với kết quả không có thật và báo hiệu nó cho hai máy khách khác. Thêm vào đó bạn sẽ không thể giải quyết lời hứa này nữa. Ngược lại, nếu bạn đã có một cặp lời hứa + người giải quyết, đã hứa với khách hàng của bạn và giữ người giải quyết cho mình thì tình huống này sẽ trở nên bất khả thi. Để biết thêm thông tin, các cụm từ tìm kiếm được đề xuất là "kiểm soát truy cập dựa trên khả năng" và "bảo mật dựa trên khả năng".
Dimagog

1
Tôi không chắc liệu việc ghép nối bảo mật với một kiểu tham chiếu đơn giản như vậy (hãy kiểm tra sự tích hợp của nó) promisecó thuận tiện hay không. Người tiêu dùng 'ác' rất hiếm; không có gì ngăn cản bạn xây dựng sự trừu tượng của riêng bạn trên những lời hứa.
vemv 29/12/12

8
Nó không phải là về bảo mật, nó chỉ xảy ra rằng lập trình dựa trên khả năng thường được mô tả liên quan đến bảo mật. Ở đây là tất cả về tính đúng đắn của mã. Thuật ngữ thường được sử dụng là "đúng bằng cách xây dựng" và câu hỏi là "bạn có thể xây dựng một chương trình không chính xác"? Không phải cố ý, mà là tình cờ. Với một đối tượng Promise duy nhất, bạn có thể làm được, trong khi với hai đối tượng riêng biệt, bạn không thể.
Dimgeon

Không có gì ngăn cản bạn từ việc trả lại một lời hứa mà không thể được giao dù là, nếu đó là những gì bạn muốn: (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

Chỉ ra sự khác biệt về cách tách rời cơ chế tính toán đã khiến bài đăng này trở thành một lời giải thích thực sự ngắn gọn. Cảm ơn!
synthomat

3

Đã có những câu trả lời xuất sắc nên chỉ thêm phần tóm tắt "cách sử dụng":

Cả hai

Tạo lời hứa hoặc tương lai trả về một tham chiếu ngay lập tức. Tham chiếu này chặn trên @ / deref cho đến khi kết quả tính toán được cung cấp bởi luồng khác.

Tương lai

Khi tạo tương lai, bạn cung cấp một công việc đồng bộ sẽ được thực hiện. Nó được thực thi trong một chuỗi từ nhóm không giới hạn chuyên dụng.

Lời hứa

Bạn không đưa ra lý lẽ khi tạo lời hứa. Tham chiếu phải được chuyển đến chuỗi 'người dùng' khác sẽ deliverdẫn đến kết quả.


1

Trong Clojure, promise, future, và delaylà lời hứa giống như các đối tượng. Tất cả chúng đều đại diện cho một tính toán mà khách hàng có thể chờ đợi bằng cách sử dụng deref(hoặc @). Khách hàng sử dụng lại kết quả, do đó tính toán không được chạy nhiều lần.

Chúng khác nhau về cách tính toán được thực hiện:

  • futuresẽ bắt đầu tính toán trong một luồng công nhân khác. derefsẽ chặn cho đến khi kết quả sẵn sàng.

  • delaysẽ thực hiện tính toán một cách lười biếng, khi khách hàng đầu tiên sử dụng derefhoặc force.

  • promisecung cấp tính linh hoạt nhất, vì kết quả của nó được phân phối theo bất kỳ cách tùy chỉnh nào bằng cách sử dụng deliver. Bạn sử dụng nó khi không futurehoặc delayphù hợp với trường hợp sử dụng của bạn.


-4

Thứ nhất, a Promiselà a Future. Tôi nghĩ bạn muốn biết sự khác biệt giữa a Promisevà a FutureTask.

A Futuređại diện cho một giá trị hiện chưa được biết nhưng sẽ được biết trong tương lai.

A FutureTaskđại diện cho kết quả của một phép tính sẽ xảy ra trong tương lai (có thể trong một nhóm luồng nào đó). Khi bạn cố gắng truy cập kết quả, nếu quá trình tính toán vẫn chưa xảy ra, nó sẽ chặn. Nếu không, kết quả được trả về ngay lập tức. Không có bên nào khác tham gia vào việc tính toán kết quả vì việc tính toán được bạn chỉ định trước.

A Promiseđại diện cho một kết quả sẽ được người quảng bá giao cho người được hứa hẹn trong tương lai. Trong trường hợp này, bạn là người hứa và người quảng bá là người đã cho bạn Promiseđồ vật. Tương tự như FutureTask, nếu bạn cố gắng truy cập kết quả trước khi kết quả Promiseđược hoàn thành, nó sẽ bị chặn cho đến khi trình quảng bá hoàn thành Promise. Sau khi Promisehoàn thành, bạn sẽ nhận được cùng một giá trị ngay lập tức. Không giống như a FutureTask, có một bên khác tham gia ở đây, một bên đã tạo ra Promise. Bên khác có trách nhiệm thực hiện tính toán và thực hiện Promise.

Theo nghĩa đó, a FutureTasklà một Promisebạn đã làm cho chính mình.


Bạn có chắc một lời hứa là một tương lai? tôi không thể thấy rằng nó thực hiện giao diện. github.com/richhickey/clojure/blob/...
Mikael Sundberg

xin lỗi, tôi nhập sai. Câu hỏi của tôi được thay đổi
Mikael Sundberg

Câu trả lời của tôi là theo nghĩa chung chung, không phải trong Clojure cụ thể.
Abhinav Sarkar

9
Trả lời một câu hỏi về Clojure với mã Java có vẻ hơi kỳ cục.
CHỈ LÀ Ý KIẾN CHÍNH XÁC CỦA TÔI
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.