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?
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?
Odpowiedzi:
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 ( :fred
w tym przypadku). Natomiast przyszłość konsumowana jest w tym samym miejscu, w którym została stworzona. Prawdopodobnie some-expr
jest 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:
promise
. Ten obiekt obietnicy można teraz przekazać do dowolnego wątku.deliver
wyniki do tego obiektu obietnicy.deref
spełnić twoją obietnicę, zanim zakończysz obliczenia, zostanie zablokowany, dopóki nie skończysz. Gdy skończysz i deliver
zrealizujesz obietnicę, obietnica nie będzie już blokowana.deref
przyszł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ął, deref
oznacza 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.
future
przypomnienia, treść rozmowy może zawierać N seksprów.
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ć deliver
jawne 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 promise
wywoł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ć.
promise
byłoby wygodne. „Zli” konsumenci są rzadkością; nic nie powstrzymuje Cię przed budowaniem własnej abstrakcji oprócz obietnic.
(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))))
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 deliver
wynik.
W Clojure, promise
, future
, i delay
to 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ń:
future
rozpocznie obliczenia w innym wątku roboczym. deref
będzie blokować, aż wynik będzie gotowy.
delay
wykona obliczenia leniwie, gdy pierwszy klient użyje deref
lub force
.
promise
oferuje największą elastyczność, ponieważ jego wynik jest dostarczany w dowolny niestandardowy sposób za pomocą deliver
. Używasz go, gdy żaden future
lub delay
pasuje do twojego przypadku użycia.
Po pierwsze, a Promise
jest Future
. Myślę, że chcesz poznać różnicę między a Promise
i a FutureTask
.
A Future
reprezentuje wartość, która nie jest obecnie znana, ale będzie znana w przyszłości.
A FutureTask
reprezentuje 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 Promise
reprezentuje 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 Promise
przedmiot. Podobnie jak w FutureTask
przypadku, jeśli spróbujesz uzyskać dostęp do wyniku, zanim Promise
zostanie spełniony, zostanie on zablokowany, dopóki obiecujący nie spełni warunku Promise
. Po Promise
speł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 FutureTask
to Promise
ty stworzone dla siebie.