Czym różnią się kontrakty terminowe i obietnice Clojure?

86

Zarówno kontrakty terminowe, jak i obietnice blokują się, dopóki nie obliczą swoich wartości, więc jaka jest różnica między nimi?

appshare.co
źródło
8
Nie jestem pewien, dlaczego -1 w pytaniu, czy też są pytania, na które nie znasz odpowiedzi, zanim zadasz teraz złe rzeczy?
TYLKO MOJA poprawna OPINIA,
Nie mam -1 żadnej odpowiedzi ?? Jak możemy stwierdzić, kto postawił -1 na quesiton lub odpowiedź?
appshare.co,
Ty i ja nie możemy, Zubair. Jestem po prostu ciekawy, kto postawił -1 na twoje pytanie, biorąc pod uwagę, że jest to całkowicie rozsądne pytanie i zdecydowanie jest na temat dla SO.
TYLKO MOJA poprawna OPINIA

Odpowiedzi:

54

Odpowiadając w kategoriach Clojure, oto kilka przykładów z screencastu Seana Devlina :

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

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

Zwróć uwagę, że w obietnicy jawnie podajesz wartość wybraną w późniejszych obliczeniach ( :fredw tym przypadku). Natomiast przyszłość konsumowana jest w tym samym miejscu, w którym została stworzona. Prawdopodobnie some-exprjest uruchamiany za kulisami i obliczany w tandemie (ostatecznie), ale jeśli pozostaje nieoceniony do czasu uzyskania dostępu do bloków wątku, dopóki nie będzie dostępny.


edytowane, aby dodać

Aby lepiej odróżnić obietnicę od przyszłości, zwróć uwagę na następujące kwestie:

obietnica

  1. Tworzysz promise. Ten obiekt obietnicy można teraz przekazać do dowolnego wątku.
  2. Kontynuujesz obliczenia. Mogą to być bardzo skomplikowane obliczenia obejmujące skutki uboczne, pobieranie danych, dane wejściowe użytkownika, dostęp do bazy danych, inne obietnice - cokolwiek chcesz. Kod będzie wyglądał bardzo podobnie do głównego kodu dowolnego programu.
  3. Kiedy skończysz, możesz deliverwyniki do tego obiektu obietnicy.
  4. Każdy element, który próbuje derefspełnić twoją obietnicę, zanim zakończysz obliczenia, zostanie zablokowany, dopóki nie skończysz. Gdy skończysz i deliverzrealizujesz obietnicę, obietnica nie będzie już blokowana.

przyszłość

  1. Tworzysz swoją przyszłość. Część twojej przyszłości jest wyrazem kalkulacji.
  2. Przyszłość może przebiegać równolegle lub nie. Można mu przypisać wątek, prawdopodobnie z puli. Mogło po prostu czekać i nic nie robić. Z twojej perspektywy nie możesz powiedzieć .
  3. W pewnym momencie Ty (lub inny wątek) jesteś derefprzyszłością. Jeśli obliczenia zostały już zakończone, otrzymasz ich wyniki. Jeśli jeszcze się nie zakończył, blokujesz, dopóki się nie skończy. (Przypuszczalnie jeśli jeszcze się nie rozpoczął, derefoznacza to, że zaczyna się uruchamiać, ale to również nie jest gwarantowane).

Podczas mógł dokonać wyraz w przyszłości tak skomplikowane jak kod, który następuje utworzenie obietnicy, to wątpliwe, że to pożądane. Oznacza to, że kontrakty futures są bardziej odpowiednie do szybkich, opartych na tle obliczeń, podczas gdy obietnice są bardziej odpowiednie dla dużych, skomplikowanych ścieżek realizacji. Również obietnice wydają się, jeśli chodzi o dostępne obliczenia, nieco bardziej elastyczne i zorientowane na twórcę obietnic wykonującego pracę i kolejny wątek zbierający plony. Futures są bardziej zorientowane na automatyczne uruchamianie wątku (bez brzydkiego i podatnego na błędy narzutu) i kontynuowanie innych rzeczy, dopóki Ty - początkowy wątek - nie będziesz potrzebować wyników.

TYLKO MOJA poprawna OPINIA
źródło
Ale możesz mieć dowolny blok obliczeniowy, dopóki obietnica ALBO przyszłość nie zostanie zakończona. czyli: (@a + @b) będzie działać tak samo zarówno z przyszłością, jak i obietnicą
appshare.co,
2
Wydaje mi się, że obietnica pozwala na większą elastyczność. Tworzę obietnicę. Przekazuję tę obietnicę do innego wątku. Mogę wtedy wykonywać wiele skomplikowanych obliczeń, w tym czekanie na I / O, pobieranie danych z Internetu, oczekiwanie na dane wejściowe użytkownika itp. Kiedy wszystko jest gotowe, dostarczam obietnicę z uzyskaną wartością. Przyszłość obejmuje jedno wyrażenie S. To mogłoby być, jak sądzę, bardzo, bardzo skomplikowane wyrażenie S, ale byłoby tam trochę ... sztywne. Ponadto przyszłość działa automatycznie w wątku (lub puli). Zrobienie tego samego w obietnicy oznaczałoby jeszcze więcej pracy.
TYLKO MOJA poprawna OPINIA,
FWIW, ponieważ pojedyncze wyrażenie s może być wywołaniem dowolnej ścieżki kodu, niekoniecznie chodzi o to, ile kodu można wcisnąć w wyrażenie. Więc zamiast mówić, że obietnica jest „bardziej elastyczna”, powiedziałbym, że jej cel jest po prostu inny. W przeciwnym razie, dlaczego oba?
Geoff
2
Dla futureprzypomnienia, treść rozmowy może zawierać N seksprów.
vemv
To wyjaśnienie powinno być częścią Clojure Doc
Piyush Katariya
25

Zarówno Future, jak i Promise to mechanizmy do przekazywania wyników obliczeń asynchronicznych od producenta do konsumenta (-ów).

W przypadku Future obliczenie jest zdefiniowany w momencie tworzenia przyszłości i asynchroniczne wykonanie zaczyna „ASAP”. „Wie” również, jak utworzyć obliczenia asynchroniczne.

W przypadku Obietnicy obliczenie jego czas rozpoczęcia i [możliwe] asynchroniczny wywołania są oddzielone od mechanizmu wprowadzającego. Gdy wynik obliczenia jest dostępny, producent musi wywołać deliverjawne wywołanie , co oznacza również, że producent kontroluje, kiedy wynik staje się dostępny.

W przypadku Promises Clojure popełnia błąd projektowy, używając tego samego obiektu (wyniku promisewywołania) zarówno do wyprodukowania ( deliver), jak i do skonsumowania ( deref) wyniku obliczeń . Są to dwie bardzo różne możliwości i tak należy je traktować.

Dimagog
źródło
@oskarkv Załóżmy, że stworzyłeś obietnicę i przekazałeś ją 3 klientom. Nic nie stoi na przeszkodzie, aby jeden z klientów rozwiązał problem z fałszywym wynikiem i zasygnalizował go dwóm innym klientom. Ponadto nie będziesz w stanie spełnić tej obietnicy. W przeciwieństwie do tego, gdybyś miał parę obietnica + przelicznik, dał obietnicę swoim klientom i zatrzymał resolver dla siebie, ten scenariusz staje się niemożliwy. Aby uzyskać więcej informacji, sugerowane terminy wyszukiwania to „kontrola dostępu oparta na możliwościach” i „bezpieczeństwo oparte na możliwościach”.
Dimagog
1
Nie jestem pewien, czy połączenie bezpieczeństwa z tak prostym typem referencyjnym (sprawdź jego impl), jak promisebyłoby wygodne. „Zli” konsumenci są rzadkością; nic nie powstrzymuje Cię przed budowaniem własnej abstrakcji oprócz obietnic.
vemv
8
Nie chodzi o bezpieczeństwo, tak się składa, że ​​programowanie oparte na możliwościach jest często opisywane w odniesieniu do bezpieczeństwa. Tutaj chodzi o poprawność kodu. Często używany termin jest „poprawny z konstrukcji”, a pytanie brzmi: „czy możesz skonstruować niepoprawny program”? Nie celowo, ale przez przypadek. Z jednym obiektem Promise możesz, podczas gdy z dwoma oddzielnymi obiektami nie możesz.
Dimagog
Nic nie (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))))
stoi na przeszkodzie, abyś zwrócił
Wskazanie różnicy, w jaki sposób mechanizm obliczeniowy jest oddzielony, sprawiło, że ten post był naprawdę zwięzłym wyjaśnieniem. Dzięki!
synthomat
3

Istnieją już doskonałe odpowiedzi, więc wystarczy dodać podsumowanie „jak korzystać”:

Obie

Tworzenie obietnicy lub przyszłości natychmiast zwraca odniesienie. To odniesienie blokuje @ / deref, dopóki inny wątek nie dostarczy wyniku obliczeń.

Przyszłość

Tworząc przyszłość, zapewniasz synchroniczne zadanie do wykonania. Jest wykonywany w wątku z dedykowanej puli nieograniczonej.

Obietnica

Tworząc obietnicę, nie podajesz żadnych argumentów. Odwołanie powinno zostać przekazane do innego wątku „użytkownika”, który da deliverwynik.

Grzegorz Luczywo
źródło
1

W Clojure, promise, future, i delayto obietnica przedmiotów podobnych. Wszystkie reprezentują obliczenia, na które klienci mogą czekać, używając deref(lub @). Klienci ponownie wykorzystują wynik, aby obliczenia nie były wykonywane kilka razy.

Różnią się sposobem wykonywania obliczeń:

  • futurerozpocznie obliczenia w innym wątku roboczym. derefbędzie blokować, aż wynik będzie gotowy.

  • delaywykona obliczenia leniwie, gdy pierwszy klient użyje dereflub force.

  • promiseoferuje największą elastyczność, ponieważ jego wynik jest dostarczany w dowolny niestandardowy sposób za pomocą deliver. Używasz go, gdy żaden futurelub delaypasuje do twojego przypadku użycia.

Ernesto
źródło
-4

Po pierwsze, a Promisejest Future. Myślę, że chcesz poznać różnicę między a Promisei a FutureTask.

A Futurereprezentuje wartość, która nie jest obecnie znana, ale będzie znana w przyszłości.

A FutureTaskreprezentuje wynik obliczenia, które nastąpi w przyszłości (może w jakiejś puli wątków). Kiedy próbujesz uzyskać dostęp do wyniku, jeśli obliczenia jeszcze się nie wydarzyły, blokuje się. W przeciwnym razie wynik jest zwracany natychmiast. Żadna inna strona nie jest zaangażowana w obliczanie wyniku, ponieważ obliczenia zostały określone przez Ciebie z góry.

A Promisereprezentuje wynik, który zostanie przekazany przez przyrzeczonego przyrzeczonemu w przyszłości. W tym przypadku jesteś obiecującym, a obiecującym jest ten, który dał ci Promiseprzedmiot. Podobnie jak w FutureTaskprzypadku, jeśli spróbujesz uzyskać dostęp do wyniku, zanim Promisezostanie spełniony, zostanie on zablokowany, dopóki obiecujący nie spełni warunku Promise. Po Promisespełnieniu warunku zawsze i natychmiast otrzymujesz tę samą wartość. W przeciwieństwie do a FutureTask, jest tu zaangażowana inna strona, która sprawiła, że Promise. Ta inna strona jest odpowiedzialna za wykonanie obliczeń i wypełnienie Promise.

W tym sensie a FutureTaskto Promisety stworzone dla siebie.

Abhinav Sarkar
źródło
Czy na pewno obietnica to przyszłość? Nie mogę stwierdzić, że implementuje interfejs. github.com/richhickey/clojure/blob/…
Mikael Sundberg
przepraszam, źle wpisałem wejście. Moje pytanie się zmieniło
Mikael Sundberg
Moja odpowiedź jest w sensie ogólnym, a nie konkretnym w Clojure.
Abhinav Sarkar,
9
Odpowiedź na pytanie o Clojure z kodem Java wydaje się nieco kapryśna.
TYLKO MOJA poprawna OPINIA,