В чем разница между Future
и Promise
?
Они оба действуют как заполнитель для будущих результатов, но в чем основное различие?
В чем разница между будущим и обещанием?
Ответы (9)
Согласно этому обсуждению, Promise
наконец-то был вызван CompletableFuture
для включения в Java 8 , и его javadoc объясняет:
Будущее, которое может быть явно завершено (установка его значения и статуса) и может использоваться как CompletionStage, поддерживающее зависимые функции и действия, которые запускаются после его завершения.
В списке также приведен пример:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Обратите внимание, что окончательный API немного отличается, но допускает аналогичное асинхронное выполнение:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
(Я пока не совсем доволен ответами, так что вот моя попытка ...)
Я думаю, что комментарий Кевина Райта («Вы можете дать обещание, и вы должны его сдержать. Когда кто-то другой дает вам обещание, вы должны подождать, чтобы увидеть, выполнят ли они его в будущем») резюмирует это довольно хорошо, но некоторые пояснения могут быть полезны.
Futures и promises - очень похожие концепции, разница в том, что будущее - это контейнер только для чтения для результата, который не пока существует, в то время как обещание может быть написано (обычно только один раз). CompletableFuture и Guava SettableFuture можно рассматривать как обещания, поскольку их ценность могут быть установлены («завершены»), но они также реализуют интерфейс Future, поэтому нет никакой разницы для клиента.
Результат будущего будет задан «кем-то другим» - результатом асинхронного вычисления. Обратите внимание, как FutureTask - классическое будущее - обязательно инициализировать с помощью Callable или Runnable, конструктора без аргументов нет, и Future, и FutureTask доступны только для чтения извне (установленные методы FutureTask защищены). Значение будет установлено на результат вычисления изнутри.
С другой стороны, результат обещания может быть установлен «вами» (или фактически кем угодно) в любое время, потому что он имеет общедоступный метод установки. И CompletableFuture, и SettableFuture можно создать без каких-либо задач, и их значение можно установить в любое время. Вы отправляете обещание клиентскому коду и выполняете его позже, когда захотите.
Обратите внимание, что CompletableFuture не является «чистым» обещанием, его можно инициализировать с помощью такой же задачи, как FutureTask, и его наиболее полезная функция - это несвязанная цепочка этапов обработки.
Также обратите внимание, что обещание не обязательно должно быть подтипом будущего и не обязательно должно быть тем же объектом. В Scala объект Future создается асинхронным вычислением или другим объектом Promise. В C ++ ситуация аналогична: объект обещания используется производителем, а объект будущего - потребителем. Преимущество такого разделения состоит в том, что клиент не может определять ценность будущего.
И Spring, и EJB 3.1 имеет класс AsyncResult, который похож на Scala / C ++. обещания. AsyncResult действительно реализует Future, но это не настоящее будущее: асинхронные методы в Spring / EJB возвращают другой объект Future только для чтения с помощью некоторой фоновой магии, и это второе «настоящее» будущее может использоваться клиентом для доступа к результату.
Я знаю, что уже есть принятый ответ, но тем не менее хотел бы добавить свои два цента:
TL; DR: Future и Promise - это две стороны асинхронной операции: потребитель / вызывающая сторона и производитель / исполнитель.
Как вызывающий метод асинхронного API, вы получите Future
как дескриптор результата вычисления. Вы можете, например, вызовите get()
на нем, чтобы дождаться завершения вычисления и получить результат.
Теперь подумайте, как на самом деле реализован этот метод API: разработчик должен немедленно вернуть Future
. Они несут ответственность за завершение этого будущего, как только будет выполнено вычисление (что они будут знать, потому что оно реализует логику отправки ;-)). Они будут использовать Promise
/ CompletableFuture
для этого: создать и немедленно вернуть CompletableFuture
и вызвать complete(T result)
после завершения вычисления.
Я приведу пример того, что такое Promise и как его значение может быть установлено в любое время, в отличие от Future, значение которого доступно только для чтения.
Предположим, у вас есть мама, и вы просите у нее денег.
// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
Supplier<Integer> momsPurse = ()-> {
try {
Thread.sleep(1000);//mom is busy
} catch (InterruptedException e) {
;
}
return 100;
};
ExecutorService ex = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> promise =
CompletableFuture.supplyAsync(momsPurse, ex);
// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
// But your father interferes and generally aborts mom's plans and
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse
// (remember the Thread.sleep(...)) :
promise.complete(10);
Результатом этого является:
Thank you mom for $10
Обещание мамы было создано, но дождалось какого-то «завершения» события.
CompletableFuture<Integer> promise...
Вы создали такое мероприятие, приняв ее обещание и объявив о своих планах поблагодарить маму:
promise.thenAccept...
В этот момент мама начала открывать сумочку ... но очень медленно ...
и отец вмешался гораздо быстрее и выполнил обещание за свою маму:
promise.complete(10);
Вы заметили исполнителя, которого я написал явно?
Интересно, что если вместо этого вы используете неявный исполнитель по умолчанию (commonPool) и отца нет дома, а только мама с ее «медленным кошельком», то ее обещание будет выполнено только в том случае, если программа живет дольше, чем нужно маме, чтобы получить деньги от кошелек.
Исполнитель по умолчанию действует как «демон» и не ждет, пока все обещания будут выполнены. Я не нашел хорошего описания этого факта ...
Не уверен, что это может быть ответ, но, поскольку я вижу, что другие сказали для кого-то, может показаться, что вам нужны две отдельные абстракции для обеих этих концепций, чтобы одна из них (Future
) была просто представлением другой только для чтения. (Promise
) ... но на самом деле это не нужно.
Например, посмотрите, как обещания определены в javascript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Основное внимание уделяется компоновке с использованием метода then
, например:
asyncOp1()
.then(function(op1Result){
// do something
return asyncOp2();
})
.then(function(op2Result){
// do something more
return asyncOp3();
})
.then(function(op3Result){
// do something even more
return syncOp4(op3Result);
})
...
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
что делает асинхронные вычисления похожими на синхронные:
try {
op1Result = syncOp1();
// do something
op1Result = syncOp2();
// do something more
op3Result = syncOp3();
// do something even more
syncOp4(op3Result);
...
console.log(result);
} catch(error) {
console.log(error);
}
что довольно круто. (Не так здорово, как async-await, но async-await просто удаляет шаблон .... then (function (result) {.... em> от этого).
И на самом деле их абстракция хороша как конструктор обещаний.
new Promise( function(resolve, reject) { /* do it */ } );
позволяет предоставить два обратных вызова, которые можно использовать для успешного завершения Promise
или с ошибкой. Так что только код, конструирующий Promise
, может его завершить, а код, который получает уже построенный объект Promise
, имеет доступ только для чтения.
С помощью наследования вышеуказанное может быть достигнуто, если resolve и reject являются защищенными методами.
CompletableFuture
может иметь некоторое сходство с Promise
, но это все равно не Promise
, потому что способ его использования отличается: результат Promise
потребляется вызовом then(function)
, а функция выполняется < i> в контексте производителя сразу после того, как производитель вызывает resolve
. Результат Future
потребляется вызовом get
, который заставляет поток-получатель ждать, пока поток-производитель не сгенерирует значение, а затем обрабатывает его в потребителе. Future
по своей природе многопоточен, но ...
- person Periata Breatta; 03.11.2016
Promise
только с одним потоком (и на самом деле это именно та среда, для которой они изначально были разработаны: приложения javascript обычно имеют только один поток, поэтому вы не можете реализовать там Future
). Promise
поэтому намного легче и эффективнее, чем Future
, но Future
может быть полезен в более сложных ситуациях, требующих взаимодействия между потоками, которые не могут быть легко организованы с помощью Promise
s. Подводя итог: Promise
- это модель выталкивания, а Future
- модель вытягивания (см. Iterable vs Observable)
- person Periata Breatta; 03.11.2016
XMLHttpRequest
). Я не верю утверждениям об эффективности, у вас есть какие-то цифры? +++ Тем не менее, очень хорошее объяснение.
- person maaartinus; 07.11.2016
get
на неразрешенном Future
обязательно будет включать 2 переключения контекста потока, что, по крайней мере, несколько лет назад, вероятно, потребовало около 50 мкс.
- person Periata Breatta; 11.11.2016
Для клиентского кода Promise предназначен для наблюдения или присоединения обратного вызова, когда доступен результат, тогда как Future ожидает результата, а затем продолжает. Теоретически все, что можно сделать с фьючерсами, можно сделать и с обещаниями, но из-за разницы в стилях результирующий API для обещаний на разных языках упрощает создание цепочек.
В интерфейсе Future нет метода set, только метод get, поэтому он доступен только для чтения. О CompletableFuture эта статья может оказаться полезной. completetablefuture
В этом примере вы можете посмотреть, как Promises можно использовать в Java для создания асинхронных последовательностей вызовов:
doSomeProcess()
.whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
.whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
.map(String::toLowerCase)
.mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
.whenResult(s -> System.out.println(s));
Future
и Promise
- прокси-объект для неизвестного результата
Promise
завершает Future
Promise
- запись / производитель неизвестного результата.Future
- чтение / получатель неизвестного результата. Имеет следующие состояния: ожидает, выполнено, отменено.
//Future has a reference to Promise
Future -> Promise
Как producer
я promise
кое-что и отвечаю за это
Как consumer
, получивший promise
, я ожидаю, что результат будет future
. В future
я могу использовать promise
или отклонить его
Что касается Java CompletableFutures
, это Promise
, потому что вы можете установить результат, а также реализует Future
Promise
, и вам решать, как его оставить. Когда кто-то другой дает вам обещание, вы должны подождать, чтобы увидеть, выполнят ли они его вFuture
- person Kevin Wright   schedule 03.02.2014