Какая разница между Future
и Promise
?
Они оба действуют как заполнитель для будущих результатов, но где основное различие?
Разница между будущим и обещанием
Ответ 1
В соответствии с этим обсуждением Promise
, наконец, был вызван CompletableFuture
для включения в Java 8 и его javadoc объясняет:
A Будущее, которое может быть явно завершено (установка его значения и статуса) и может использоваться как CompletionStage, поддерживая зависимые функции и действия, которые запускаются после его завершения.
Пример также указан в списке:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Обратите внимание, что конечный API немного отличается, но позволяет подобное асинхронное выполнение:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
Ответ 2
(Я до сих пор не доволен ответами, поэтому вот моя попытка...)
Я думаю, что комментарий Кевина Райт ( "Вы можете сделать обещание, и это зависит от вас, чтобы сохранить его. Когда кто-то сделает вам обещание, вы должны подождать, чтобы удостовериться, что они почитают его в будущем" ) резюмирует его довольно хорошо, но может быть полезно некоторое объяснение.
Фьючерсы и promises - довольно похожие понятия, разница в том, что будущее является контейнером только для чтения, для результата, которого еще нет, а обещание может быть написано (обычно только один раз). Java 8 CompletableFuture и Guava SettableFuture можно охарактеризовать как promises, потому что их значение могут быть установлены ( "завершены" ), но они также реализуют интерфейс Future, поэтому для клиента нет никакой разницы.
Результат будущего будет задан "кем-то другим" - результатом асинхронного вычисления. Обратите внимание, что FutureTask - классическое будущее - должно быть инициализировано с помощью Callable или Runnable, нет конструктора без аргументов, и как Future, так и FutureTask доступны только для чтения извне (заданные методы FutureTask защищены). Значение будет установлено на результат вычисления изнутри.
С другой стороны, результат обещания может быть задан "вы" (или фактически кем-либо) в любое время, потому что у него есть общедоступный метод setter. Оба CompletableFuture и SettableFuture могут быть созданы без какой-либо задачи, и их значение может быть установлено в любое время. Вы отправляете обещание на код клиента и выполняете его позже, как пожелаете.
Обратите внимание, что CompletableFuture не является "чистым" обещанием, его можно инициализировать с помощью задачи, аналогичной FutureTask, и ее наиболее полезной функцией является несвязанная цепочка шагов обработки.
Также обратите внимание, что обещание не обязательно должно быть подтипом будущего, и он не должен быть одним и тем же объектом. В Scala объект Future создается асинхронным вычислением или другим объектом Promise. В С++ ситуация аналогична: объект обещания используется производителем и будущим объектом потребителем. Преимущество этого разделения заключается в том, что клиент не может установить ценность будущего.
Оба Spring и EJB 3.1 имеют класс AsyncResult, который похож на Scala/С++ promises. AsyncResult реализует Future, но это не настоящее будущее: асинхронные методы в Spring/EJB возвращают другой объект Future-only для чтения с помощью некоторой фоновой магии, и это второе "реальное" будущее может использоваться клиентом для доступа к результат.
Ответ 3
Я знаю, что уже есть принятый ответ, но хотелось бы добавить мои два цента:
Как вызывающий метод асинхронного API, вы получите Future
как дескриптор результата вычисления. Вы можете, например, вызовите get()
, чтобы дождаться завершения вычисления и получения результата.
Теперь подумайте, как этот метод API фактически реализован: разработчик должен немедленно вернуть Future
. Она отвечает за завершение этого будущего, как только будет сделано вычисление (которое она будет знать, потому что она реализует логику отправки;-)). Она будет использовать Promise
/ CompletableFuture
, чтобы сделать именно это: немедленно создать и вернуть CompletableFuture
и вызвать complete(T result)
после выполнения вычисления.
TL;DR: будущее и обещание - это две стороны асинхронной операции: потребитель/вызывающий и производитель/разработчик.
Ответ 4
Я приведу пример того, что такое обещание, и как его значение может быть установлено в любое время, в противоположность Будущему, значение которого доступно только для чтения.
Предположим, у вас есть мама, и вы просите у нее денег.
Теперь вы обманываете свою маму, создавая вам обещание возможного пожертвования, она дает вам этот объект обещания, но она не очень опрометчиво, чтобы выполнить ее еще:
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);
Вы счастливы, вы берите, чтобы поблагодарить вас, ваша мама:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
Но ваш отец вмешивается и вообще прекращает планы мамы и завершает обещание (устанавливает его ценность!) с гораздо меньшим вкладом, как и отцы, очень решительно, в то время как мама медленно открывает свой кошелек (обратите внимание на Thread.sleep(... )):
promise.complete(10);
Вывод:
Thank you mom for $10
Обещание мамы было создано, но ждало какое-то событие "завершения".
CompletableFuture<Integer> promise...
Вы создали такое событие, приняли свое обещание и объявили о своих планах поблагодарить свою маму:
promise.thenAccept...
В этот момент мама начала открывать кошелек... но очень медленно...
и отец вмешался намного быстрее и выполнил обещание вместо вашей мамы:
promise.complete(10);
Вы заметили исполнителя, который я написал явно? Интересно, что если вместо этого использовать вместо него неявный исполнитель (commonPool), а отца нет дома, только мама с ее "медленным кошельком", то ее обещание будет завершено, если в программе больше времени, чем маме, нужно получить деньги от Кошелек. Я имею в виду, что исполнитель по умолчанию действует как "демон". Я не нашел хорошего описания этого факта...
Ответ 5
Не уверен, что это может быть ответ, но, поскольку я вижу, что другие сказали для кого-то, может показаться, что вам нужны две отдельные абстракции для обеих этих концепций, так что один из них (Future
) является просто средством чтения- только вид другого (Promise
)... но на самом деле это не требуется.
Например, посмотрите, как promises определены в 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-wait, но async-wait просто удаляет шаблон... затем (функция (результат) {.... от него).
И на самом деле их абстракция довольно хороша, как конструктор обещаний
new Promise( function(resolve, reject) { /* do it */ } );
позволяет вам предоставить два обратных вызова, которые могут быть использованы для успешного завершения Promise
или с ошибкой. Так что только код, который создает Promise
, может завершить его, а код, который получает уже построенный объект Promise
, имеет вид только для чтения.
С наследованием вышесказанное может быть достигнуто, если методы разрешения и отклонения защищены.
Ответ 6
Отсутствует установленный метод в интерфейсе Future, только получите метод, поэтому он доступен только для чтения. О CompletableFuture, эта статья может быть полезной. completablefuture
Ответ 7
Для клиентского кода Promise предназначена для наблюдения или привязки обратного вызова, когда результат доступен, тогда как Future должен ждать результата, а затем продолжить. Теоретически все, что можно сделать с фьючерсами, что можно сделать с помощью promises, но из-за различий в стиле результирующий API для promises на разных языках упрощает цепочку.