Jaka jest różnica między Future
i Promise
?
Oba działają jak symbol zastępczy dla przyszłych wyników, ale gdzie jest główna różnica?
java
concurrency
future
promise
użytkownik1170330
źródło
źródło
Promise
i to zależy od ciebie, aby go zatrzymać. Gdy ktoś inny złoży ci obietnicę, musisz poczekać, aby zobaczyć, czy ją dotrzymaFuture
Odpowiedzi:
Według tej dyskusji ,
Promise
w końcu został powołanyCompletableFuture
do włączenia w Java 8, a jego javadoc wyjaśnia:Przykład podano również na liście:
Pamiętaj, że końcowy interfejs API jest nieco inny, ale umożliwia podobne wykonywanie asynchroniczne:
źródło
(Jak dotąd nie jestem do końca zadowolony z odpowiedzi, więc oto moja próba ...)
Myślę, że komentarz Kevina Wrighta ( „Możesz złożyć obietnicę, a dotrzymanie jej zależy od ciebie. Gdy ktoś inny złoży ci obietnicę, musisz poczekać, czy ją dotrzyma w przyszłości” ) dość dobrze ją podsumowuje, ale niektóre wyjaśnienie może być przydatne.
Futures i obietnice są dość podobnymi koncepcjami, różnica polega na tym, że przyszłość jest pojemnikiem tylko do odczytu dla wyniku, który jeszcze nie istnieje, podczas gdy obietnica może być napisana (zwykle tylko raz). Java 8 CompletableFuture i Guava SettableFuture można traktować jako obietnice, ponieważ ich wartość można ustawić („ukończono”), ale implementują one również interfejs Future, dlatego nie ma różnicy dla klienta.
Wynik przyszłości zostanie ustalony przez „kogoś innego” - na podstawie obliczeń asynchronicznych. Zwróć uwagę, że FutureTask - klasyczna przyszłość - musi zostać zainicjalizowany za pomocą Callable lub Runnable, nie ma konstruktora bez argumentów, a Future i FutureTask są tylko do odczytu z zewnątrz (ustawione metody FutureTask są chronione). Wartość zostanie ustawiona na wynik obliczeń od wewnątrz.
Z drugiej strony, wynik obietnicy może być ustawiony przez „ciebie” (a właściwie przez kogokolwiek) w dowolnym momencie, ponieważ ma on metodę publicznego ustawiania. Zarówno CompletableFuture, jak i SettableFuture można tworzyć bez żadnego zadania, a ich wartość można ustawić w dowolnym momencie. Wysyłasz obietnicę do kodu klienta i wypełniasz ją później, jak chcesz.
Należy pamiętać, że CompletableFuture nie jest „czystą” obietnicą, można ją zainicjować za pomocą zadania takiego jak FutureTask, a jej najbardziej użyteczną funkcją jest niepowiązane tworzenie łańcuchów etapów przetwarzania.
Zauważ też, że obietnica nie musi być podtypem przyszłości i nie musi być tym samym przedmiotem. W Scali przyszły obiekt jest tworzony przez obliczenia asynchroniczne lub inny obiekt Promise. W C ++ sytuacja jest podobna: obiekt przyrzeczenia jest używany przez producenta, a obiekt przyszły przez konsumenta. Zaletą tego rozdzielenia jest to, że klient nie może ustalić wartości przyszłości.
Zarówno Spring, jak i EJB 3.1 mają klasę AsyncResult, która jest podobna do obietnic Scala / C ++. AsyncResult implementuje Future, ale to nie jest prawdziwa przyszłość: metody asynchroniczne w Spring / EJB zwracają inny obiekt Future tylko do odczytu poprzez magię tła, a ta druga „prawdziwa” przyszłość może zostać wykorzystana przez klienta w celu uzyskania dostępu do wyniku.
źródło
Wiem, że odpowiedź jest już zaakceptowana, ale mimo to chciałbym dodać dwa centy:
TLDR: Przyszłość i obietnica to dwie strony działania asynchronicznego: konsument / rozmówca vs. producent / realizator .
Jako wywołujący metodę asynchronicznego interfejsu API otrzymasz
Future
uchwyt do wyniku obliczeń. Możesz np. Zadzwonićget()
, aby poczekać na zakończenie obliczeń i pobrać wynik.Pomyśl teraz o tym, jak ta metoda API jest faktycznie zaimplementowana: implementator musi
Future
natychmiast zwrócić . Są odpowiedzialni za ukończenie tej przyszłości, jak tylko obliczenia zostaną wykonane (co będą wiedzieć, ponieważ implementuje logikę wysyłki ;-)). UżyjąPromise
/,CompletableFuture
aby to zrobić: Skonstruuj i zwróćCompletableFuture
natychmiast, i zadzwońcomplete(T result)
po zakończeniu obliczeń.źródło
Podam przykład tego, czym jest Obietnica i jak można ustawić jej wartość w dowolnym momencie, w przeciwieństwie do Przyszłości, której wartość można odczytać.
Załóżmy, że masz mamę i prosisz ją o pieniądze.
Wynikiem tego jest:
Obietnica mamy została stworzona, ale czekała na jakieś „zakończenie”.
Stworzyłeś takie wydarzenie, akceptując jej obietnicę i ogłaszając plany podziękowania mamie:
W tym momencie mama zaczęła otwierać torebkę ... ale bardzo powoli ...
a ojciec interweniował znacznie szybciej i wypełnił obietnicę zamiast twojej mamy:
Czy zauważyłeś wykonawcę, który napisałem wyraźnie?
Co ciekawe, jeśli zamiast tego użyjesz domyślnego domyślnego modułu wykonującego (commonPool), a ojca nie ma w domu, ale tylko mama z jej „powolną torebką”, wówczas jej obietnica się spełni, jeśli program żyje dłużej niż mama potrzebuje pieniędzy z portmonetka.
Domyślny moduł wykonujący działa jak „demon” i nie czeka na spełnienie wszystkich obietnic. Nie znalazłem dobrego opisu tego faktu ...
źródło
Nie jestem pewien, czy może to być odpowiedź, ale jak widzę, co inni powiedzieli dla kogoś, może to wyglądać tak, jakbyś potrzebował dwóch oddzielnych abstrakcji dla obu tych pojęć, tak aby jedna z nich (
Future
) była tylko widokiem do odczytu drugiej (Promise
) ... ale tak naprawdę nie jest to potrzebne.Na przykład spójrz, jak obietnice są zdefiniowane w javascript:
https://promisesaplus.com/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Nacisk kładziony jest na kompozycję przy użyciu
then
metody takiej jak:co sprawia, że obliczenia asynchroniczne wyglądają jak synchroniczne:
co jest całkiem fajne. (Nie tak fajne, jak async-czekaj, ale async-czekaj po prostu usuwa płytkę kotła .... wtedy (funkcja (wynik) {.... z niej).
W rzeczywistości ich abstrakcja jest całkiem dobra jako konstruktor obietnic
pozwala podać dwa oddzwaniania, których można użyć do
Promise
pomyślnego ukończenia lub z błędem. Tak więc tylko kod, który konstruuje,Promise
może go ukończyć, a kod, który odbiera już skonstruowanyPromise
obiekt, ma widok tylko do odczytu.Dzięki dziedziczeniu powyższe można osiągnąć, jeśli rozwiązania i odrzucenia są chronionymi metodami.
źródło
CompletableFuture
może mieć pewne podobieństwo doPromise
ale ,Promise
ale nadal tak nie jest , ponieważ sposób, w jaki ma być spożywany, jest inny:Promise
wynik jest zużywany przez wywołaniethen(function)
, a funkcja jest wykonywana w kontekście producenta natychmiast po wywołaniu przez producentaresolve
.Future
Wynik jest zużywana jest przez wywołanieget
co powoduje nić konsumentów czekać aż gwint producent wygenerował wartość, a następnie przetwarza je na konsumenta.Future
jest z natury wielowątkowy, ale ...Promise
tylko jednego wątku (w rzeczywistości jest to dokładne środowisko, dla którego zostały pierwotnie zaprojektowane: aplikacje javascript mają zazwyczaj tylko jeden wątek, więc nie możnaFuture
tam zaimplementować ).Promise
jest zatem znacznie lżejszy i wydajniejszy niżFuture
, aleFuture
może być pomocny w sytuacjach, które są bardziej złożone i wymagają współpracy między wątkami, których nie można łatwo za pomocąPromise
s. Podsumowując:Promise
jest modelem push, podczas gdyFuture
jest modelem pull (por. Iterable vs Observable)XMLHttpRequest
). Nie wierzę w deklarację efektywności, czy zdarza ci się mieć jakieś liczby? +++ To powiedziawszy, bardzo miłe wytłumaczenie.get
do nierozwiązaniaFuture
będzie wymagało 2 przełączników kontekstowych wątków, co przynajmniej kilka lat temu prawdopodobnie wymagałoby około 50 nas .W przypadku kodu klienta Promise służy do obserwowania lub dołączania oddzwaniania, gdy wynik jest dostępny, natomiast Future ma czekać na wynik, a następnie kontynuować. Teoretycznie wszystko, co można zrobić z przyszłością, co można zrobić z obietnicami, ale ze względu na różnicę stylu wynikowe API dla obietnic w różnych językach ułatwia tworzenie łańcuchów.
źródło
Brak metody ustawionej w interfejsie Future, tylko metoda get, więc jest tylko do odczytu. O CompletableFuture ten artykuł może być pomocny. pełna przyszłość
źródło